
// AJOUT 2.5.3: Fonctions de traçage
var _bLog = false;	// ACTIVER CE BOOLEEN POUR LE DEBUG
var _oLog = null;
var _iLogLine = 0;

// AJOUT 2.5.3: Variable mise à true à la fin du chargement de la page.
// Permet d'être sûr que la page est terminée de charger avant d'afficher des infobulles
var _bLoaded = false;

function __CREATE_LOG_DIV__() {
	if (! _oLog) {
		_oLog = document.createElement('div');
		document.body.insertBefore(_oLog, null);
	}
}

function __LOG__(strMessage) {
	if (_bLog) {
		__CREATE_LOG_DIV__();
		
		_iLogLine ++;
	
		_oLog.innerHTML += _iLogLine.toString() + ' : ' + strMessage + '<br />';
	}
}

function __LOG_CLEAR__() {
	if (_bLog) {
		__CREATE_LOG_DIV__();
		_oLog.innerHTML = '';
	}
}
///

// AJOUT 2.5.3: Verrouillage pour éviter empilement d'actions
var _bWorking = false;
var _bWorkingTimer = 0;

function startWorking() {
	if (_bWorkingTimer) clearTimeout(_bWorkingTimer);

	_bWorking = true;
	
	// Lance un timer pour débloquer au cas où
	_bWorkingTimer = setTimeout('_bWorking = false;', 10000);
}

function stopWorking() {
	if (_bWorkingTimer) clearTimeout(_bWorkingTimer);
	_bWorking = false;
}

// DEPLACEMENT 2.5.4
function selectActiveField() {
	if (_ipb) {
		if (! _vr) {
			var oCtrl = document.getElementById(_pbs);
			var bInput = true;
			if (oCtrl) {
			  	if (oCtrl.type && oCtrl.type != "hidden") {
				  oCtrl.focus();
				} else {
					bInput = false;
				}
			} else {
				bInput = false;
			}
			
			if (_ppos) document.body.scrollTop = _ppos;
		}
	}
}


// Génération de la fonction Javascript de gestion du postback
function throwPostBack(strID, bDoNotSubmit) {
	var oForm = document.getElementById("MainForm");
	var oSource = document.getElementById("__PostBackSource");
	oSource.value = strID;
	MainForm_onSubmit();
	if (! bDoNotSubmit) oForm.submit();
	return false;
}

// Génération de la fonction Javascript de gestion du postback pour les champs agregés des repeaters
function throwAction(strAction, strParam) {
	var oForm = document.getElementById("MainForm");
	var oSource = document.getElementById("__PostBackSource");
	var oParam = document.getElementById("__ActionParam");
	oSource.value = strAction;
	oParam.value = strParam;
	MainForm_onSubmit();
	oForm.submit();
}

// AJOUT 2.5 
// Alias de throwAction pour alleger les pages
function ta(strAction, strParam) {
	throwAction(strAction, strParam);
}

// Code appelé à la soumission du formulaire	// Déplacement 2.5
function MainForm_onSubmit() {
	// Place la position de la page dans le champ __PagePosition
	oField = document.getElementById('__PagePosition');
	oField.value = document.body.scrollTop;
}

//// Fonction base64encode ////
// Encode une chaîne en base64 "version ps2" c'est à dire avec remplacement des + et des /
////////////////////////////
// AJOUT 2.5
function base64PSencode(strVal) {
	strVal = Base64.encode(strVal);
	
	// Surencode les + et les / en utilisant _ et -
	strVal = strVal.replace('+', '_');
	strVal = strVal.replace('/', '-');
	
	return strVal;
}

////////////////////// Fonctions liées au contrôle webMenu //////////////////////

//// Fonction __WebMenu_keepVisible ////
// S'assure que le sous menu donné reste visible
////////////////////////////
// AJOUT 2.5
function __WebMenu_keepVisible(strID, iLevel, aTimer, aActivatedItems) {
	var oMenu = document.getElementById(strID);
	
	__WebMenu_cancelHide(aTimer, aActivatedItems);

	oMenu.style.visibility = 'visible';
	aActivatedItems[iLevel] = strID;
}

//// Fonction  __WebMenu_selItem ////
// Selectionne un élément de menu dans un WebMenu
////////////////////////////
function __WebMenu_selItem(strID, iLevel, iSub, aTimer, aActivatedItems) {  // Modif V2.5
	var oItem = document.getElementById(strID);
	var oMenu = document.getElementById(strID+"_s"); // Modif V2.5

	
	__WebMenu_cancelHide(aTimer, aActivatedItems);
	
	for (iIndex = iLevel; iIndex < aActivatedItems.length; iIndex ++) {
		oSubMenu = document.getElementById(aActivatedItems[iIndex]);
		if (oSubMenu) oSubMenu.style.visibility = 'hidden';
	}
	if (oItem && oMenu) {
		if (!iSub) {
			oMenu.style.left = getLeft(oItem);
			oMenu.style.top = getTop(oItem) + oItem.offsetHeight;// + 2;
		}
		else {
			oMenu.style.left = getLeft(oItem) + oItem.offsetWidth + 1;
			oMenu.style.top = getTop(oItem) - 1;
		}
		oMenu.style.visibility = 'visible';
		aActivatedItems[iLevel] = strID + "_s"; // Modif V2.5
	}
}

//// Fonction  __WebMenu_hideAll ////
// Lance le timer déclenchant la commande de masquage des menus
////////////////////////////
function __WebMenu_hideAll(strVarTimer, strVarActivatedItems) {
	for (iIndex = eval(strVarActivatedItems).length - 1; iIndex >= 0; iIndex--) {
		strID = eval(strVarActivatedItems)[iIndex];
		if (strID) {
			eval(strVarTimer)[iIndex] = setTimeout('__WebMenu_hideSubMenu("'+strID+'", '+iIndex+',"'+strVarTimer+'","'+strVarActivatedItems+'");',200);
		}
	}
}

//// Fonction  __WebMenu_cancelHide ////
// Annule le timer déclenchant la commande de masquage des menus
////////////////////////////
function __WebMenu_cancelHide(aTimer, aActivatedItems) {
	for (iIndex = 0; iIndex <= aTimer.length; iIndex++) {
		if (aTimer[iIndex]) {
			clearTimeout(aTimer[iIndex]);
		}
	}
}

//// Fonction  __WebMenu_hideSubMenu ////
// Masque un sous menu dans un WebMenu
////////////////////////////
function __WebMenu_hideSubMenu(strID, iLevel, strVarTimer, strVarActivatedItems) {
	oSubMenu = document.getElementById(strID);
	if (oSubMenu) oSubMenu.style.visibility = 'hidden';
	eval(strVarActivatedItems)[iLevel] = '';
}

//////////////////////////////////////////////////////////////////////////////////


function verifDate_old(date){
	if (date=="JJ/MM/AAAA"){
		return true;
	}
	var array=date.split("/");
	if (array.length!=3){
		return false;
	}
	for (i=0;i<3 ;i++ ){
		if(array[i].length==0){
			return false;
		}
	}
	
    var j,m,a,d2,maxj;
	j=parseInt(array[0],10);
	m=parseInt(array[1],10);
	if (m<1 || m>12){
		return false;
	}
	if (array[2].length<4){//on met la date sur 4chiffres
		a=2000+parseInt(array[2],10);
		//date1.value=array[0]+"/"+array[1]+"/"+a;
	}
	else if(array[2].length>4){
		return false;
	}
	else{
		a=parseInt(array[2],10);
	}
	if (m==2){ //fevrier
		if ((a % 4) == 0) {
			if (j>29){
				return false;
			}
		}
		else{
			if (j>28){
				return false;
			}
		}
	}
	// modif Fch 11/04/2005: ajout vérif sur nombre de jours hors février
	else if (m==1 || m==3 || m==5 || m==7 || m==8 || m==10 || m==12) {
		if (j>31) return false;
	}
	else {
		if (j>30) return false;
	}
	return true;
}

//Fonction permettant de connaître la position d'un objet
//par rapport au bord gauche de la page.
//Cet objet peut être à l'intérieur d'un autre objet.
function getLeft(MyObject) {
	if (MyObject.offsetParent)
		return (MyObject.offsetLeft + getLeft(MyObject.offsetParent));
	else
		return (MyObject.offsetLeft);
}
//Fonction permettant de connaître la position d'un objet
//par rapport au bord haut de la page.
//Cet objet peut être à l'intérieur d'un autre objet.
function getTop(MyObject) {
	if (MyObject.offsetParent)
		return (MyObject.offsetTop + getTop(MyObject.offsetParent));
	else
		return (MyObject.offsetTop);
}


//// Fonction  __WebMultiSelect_move ////
// Déplace les éléments sélectionnés d'une liste vers une autre liste
////////////////////////////
function __WebMultiSelect_move(l1,l2,limit,msg) {
	var i;

	for (i=0; i<l1.length; i++){
		if(l1.options[i].selected){
		    if (l2.length==limit && limit != 0) {
				alert(msg);
				return false;
			}
			var o=new Option(l1.options[i].text,l1.options[i].value);

			l2.options[l2.options.length]= o;
			l1.options[i]= null;
			i--; // puisqu'on a supprimé une valeur, l'indice a diminué de 1
		}
	}
}

//// Fonction  __WebMultiSelect_moveAll ////
// Déplace tous les éléments d'une liste vers une autre liste
////////////////////////////
function __WebMultiSelect_moveAll(l1,l2,limit,msg) {			// MODIF 2.4.3
	while (l1.options.length > 0) {
		// AJOUT 2.4.3
	    if (l2.length==limit && limit != 0) {
			alert(msg);
			return false;
		}
	
		o=new Option(l1.options[0].text,l1.options[0].value);
		l2.options[l2.options.length]=o;
		l1.options[0]=null;
	}
}

//// Fonction  __WebMultiSelect_up ////
// Monte un élément dans une liste
////////////////////////////
function __WebMultiSelect_up(liste) {
	var idx = liste.options.selectedIndex;
	if (idx>=1) {
		// echange avec l'élement juste au dessus
		o1=new Option(liste.options[idx].text,liste.options[idx].value);
		o2=new Option(liste.options[idx-1].text,liste.options[idx-1].value);
		liste.options[idx]=o2;
		liste.options[idx-1]=o1;
		// selectionne le nouvel indice
		liste.options.selectedIndex=idx-1;
	}
}

//// Fonction  __WebMultiSelect_down ////
// Descend un élément dans une liste
////////////////////////////
function __WebMultiSelect_down(liste) {
	var idx = liste.options.selectedIndex;
	if (idx<liste.options.length-1) {
		// echange avec l'élement juste au dessous
		o1=new Option(liste.options[idx].text,liste.options[idx].value);
		o2=new Option(liste.options[idx+1].text,liste.options[idx+1].value);
		liste.options[idx]=o2;
		liste.options[idx+1]=o1;
		// selectionne le nouvel indice
		liste.options.selectedIndex=idx+1;
	}
}

//// Fonction  __WebRepeater_gotopage ////
// Changement de page dans un repeater
////////////////////////////
// AJOUT 2.5
function __WebRepeater_gotopage(iID, iNum) {
	oTxt = document.getElementById(iID);
	oTxt.value = iNum;
	throwPostBack(iID);
}

//// Fonction  __WebRepeater_sort ////
// Tri dans un repeater
////////////////////////////
// AJOUT 2.5
function __WebRepeater_sort(iID, strCol) {
	throwAction(iID + '_sort', strCol);
}

//// Fonction  __CR_selectAll ////
// Select all sur les cases d'un custom repeater
////////////////////////////
// AJOUT 2.5
function __CR_selectAll(iID, bSelect) {
	var aoCheckBoxes = document.getElementsByName(iID + '_chk[]');
	if (aoCheckBoxes) {
		for (iElem = 0; iElem < aoCheckBoxes.length; iElem ++) {
			// coche la checkbox correspondante
			aoCheckBoxes[iElem].checked = bSelect;
		}
	}
}

//// Fonction  __CR_getSelected ////
// Fonction de récupération des checkbox sélectionnées dans un custom repeater
////////////////////////////
// AJOUT 2.5
function __CR_getSelected(iID) {
	var aoCheckBoxes = document.getElementsByName(iID + '_chk[]');
	var strResult = "";
	if (aoCheckBoxes) {
		for (iElem = 0; iElem < aoCheckBoxes.length; iElem ++) {
			if (aoCheckBoxes[iElem].checked) {
			if ((iElem != 0) && (strResult!="")) strResult += ",";
				strResult += aoCheckBoxes[iElem].value;
			}
		}
	}
	return strResult;
}

// Fonction is_array (Ajuot 2.4)
function is_array(obj) {
	return (obj instanceof Array || obj.constructor == Array);
}

// Fonction d'affichage d'un Div
// OBSOLETE 2.5.4
// IMPORTANT: L'objectif est de se débarasser à terme de cette fonction donc surtout ne pas crééer de nouveaux développements qui l'utilisent
// A la place utiliser le système d'infobulles (dans psifb.js)
function showDiv(oElem, strContent, strID, bPositionAuto) {
	if (!strContent) return false;
	oDiv = document.getElementById(strID+"_div");

	oDivContent = document.getElementById(strID+"_divcontent");
	if (oDiv && oDivContent && oDiv.style.visibility != "visible") {
		oDivContent.innerHTML = strContent;
		
		// Ajuste la largeur de la Div parente pour s'adapter au divcontent
		if (bPositionAuto) {
			iLeft = getLeft(oElem) - oDiv.offsetWidth;
			if (iLeft < 0) {
				iLeft = getLeft(oElem) + oElem.offsetWidth;
			}
			oDiv.style.left = iLeft;
			oDiv.style.top = getTop(oElem);
		}
		else {
			oDiv.style.left = getLeft(oElem) - oDiv.offsetWidth;
			oDiv.style.top = getTop(oElem) - oDiv.offsetHeight;
		}
		oDiv.style.visibility = "visible";
	}
}

// Fonction de masquage du Div
function hideDiv(strID) {
	oDiv = document.getElementById(strID + "_div");
	if (oDiv) {
		oDiv.style.visibility = "hidden";
	}
}

// Gestion d'infobulles multiples numerotées dans la page
var _aoTimerInfobulles = new Array();	// Timers liés à la fermeture des infobulles
var _aoInfobulles = new Array();		// Tableau contenant les div d'infobulles
var _iInfobulles = 0;					// Dernière indice d'infobulle
var _aiInfobullesLock = new Array();	// Tableau des indices d'infobulle qui sont lockés (= en mode popup)
var _astrInfobullesTags = new Array();	// Tableau des tags des infobulles (pour éviter ouvertures multiples d'une même infobulle)
var _aiInfobullesIndexTags = new Array();	// Tableau de correspondance index <-> tags


// Suppression d'une infobulle
function deleteInfobulle(iInfobulles, bForce) {
	if (! _bLoaded) return;
	
	if (iInfobulles == null) {
		// Dans ce cas on supprime la dernière infobulle créée
		iInfobulles = _iInfobulles;
		
		__LOG__(iInfobulles.toString() + ': Suppression du dernier index d\'infobulle');
	}
	
	// Si l'infobulle n'existe déjà plus, on quitte
	if (_aoInfobulles[iInfobulles]) {
		// On ne ferme que si forcé ou pas dans les notés comme lockés
		if (_aiInfobullesLock[iInfobulles] == false || bForce) {
			oDiv = _aoInfobulles[iInfobulles];
			strTag = _aiInfobullesIndexTags[iInfobulles];

			if (bForce) {
				// Annule les éventuelles suppressions retardées
				cancelHide(iInfobulles);
				
				// Suppression directe
				document.body.removeChild(oDiv);
				_aoInfobulles[iInfobulles] = null;
				_aiInfobullesLock[iInfobulles] = false;
				if(strTag) _astrInfobullesTags[strTag] = false;
			}
			else {
				_aoTimerInfobulles[iInfobulles] = setTimeout('if (_aoInfobulles[iInfobulles]) document.body.removeChild(_aoInfobulles[iInfobulles]); _aoInfobulles[iInfobulles] = null; _aiInfobullesLock[iInfobulles] = false; if(strTag) _astrInfobullesTags[strTag] = false;', 500);
			}
		}
	}
	else {
		__LOG__(iInfobulles.toString() + ': Impossible de fermer: infobulle supprimee');
	}

}

// Annulation du masquage d'une infobulle
function cancelHide(iInfobulles) {
	if (! _bLoaded) return;
	
	if (_aoTimerInfobulles[iInfobulles] != null) {
		clearTimeout(_aoTimerInfobulles[iInfobulles]);
	}
}

// Affichage d'une pseudo popup avec un div		(Ajout 2.4)
function showDivPopup(strID, strMethod, astrParams, strPosition) {

	stopWorking();	// Action prioritaire
	
	// Masque la dernière div ouverte
	deleteInfobulle(null, true);

	strContent = getServerRequest(strMethod, astrParams);


	oDiv = document.getElementById(strID+"_div");
	oDivContent = document.getElementById(strID+"_divcontent");
	oDivHandle = document.getElementById(strID+"_handle");
	
	oDivContent.innerHTML = strContent;

	if (strPosition == 'center') {
		// Calcule la position du Div pour qu'il soit centré
		// MODIF 2.5.1: Prend en compte le scroll
		var iTop;
		var iLeft;
		iTop = getScrollTop() - 50 + (0.5 * (screen.height - oDiv.offsetHeight));
		iLeft = 0.5 * (screen.availWidth - oDiv.offsetWidth);
		
		oDiv.style.top =  iTop.toString() + 'px';
		oDiv.style.left = iLeft.toString() + 'px';	
	}
	
	oDiv.style.visibility = "visible";
	
	// AJOUT 2.5.3: Active le Drag & Drop
	if (oDivHandle) __WebPopup_dragdrop(strID);
}

// AJOUT 2.5.1
function getScrollTop() {
	if (window.pageYOffset) {
    	return window.pageYOffset;
    }
    if(document.body) {
    	return document.body.scrollTop;
    }
    
   	return 0;
}


// Récupère les valeurs en court de tous les inputs et selects	(Ajout 2.4)
function getValeursInputs(strID) {
	var s = '';
	var aParams = new Object();	// On utilise un Object pour une associative array	 

	// Ne récupère que ce qui est contenu dans l'élément passé en argument
	var oElem = document.getElementById(strID);
	
	construitValeursTag(oElem, aParams, 'input');
	construitValeursTag(oElem, aParams, 'select');
	construitValeursTag(oElem, aParams, 'textarea');
	
	// Construit la chaîne à partir du tableau
	for(var strKey in aParams) {
		var strValue = aParams[strKey];

		if (s) s += '&';
		
		if (is_array(strValue)) {
			// Tableau, il faut utiliser la notation avec crochets
			for (iCount = 0; iCount < strValue.length; iCount++) {
				if (iCount) s += '&';
				
				s += s + '[]=' +  escape(strValue[iCount]);		
			}
		}
		else {
			// Valeur scalaire
			s += strKey + '=' + escape(strValue);
		}
	}
	
	return s;
}

// Construit le tableau des valeurs pour un type de tag HTML particulier (Ajout 2.4)
function construitValeursTag(oElem, aParams, strTagType) {
	
	// Tableau des inputs du document
	var aoInputs = oElem.getElementsByTagName(strTagType);
	
	// Boucle sur les inputs pour créer un tableau associatif (permet de gérer les champs à valeurs multiples
	for (iCount = 0; iCount < aoInputs.length; iCount++) {
		if (aoInputs[iCount].name) {
			// MODIF 2.5.3: Pour les champs checkbox, on ne garde que ce qui est sélectionné
			if (! (aoInputs[iCount].type == 'checkbox' && !aoInputs[iCount].checked)) {
				
				if (aParams[aoInputs[iCount].name]) {
					// Gère la valeur multiple
					if (is_array(aParams[aoInputs[iCount].name])) {
						// Déjà un tableau, on ajoute à la fin
						aParams[aoInputs[iCount].name][aParams[aoInputs[iCount].name].length] = 'base64:' + base64PSencode(aoInputs[iCount].value);	// MODIF 2.4.3	// MODIF 2.5
					}
					else {
						// Valeur scalaire, on construit un nouveau tableau
						var strOld = aParams[aoInputs[iCount].name];
						var aNew = new Array();
						aNew[aNew.length] = strOld;
						aNew[aNew.length] = 'base64:' + base64PSencode(aoInputs[iCount].value);	// MODIF 2.4.3 // MODIF 2.5
						aParams[aoInputs[iCount].name][aParams[aoInputs[iCount].name].length] = aNew;
					}
				}
				else {
					// N'existe pas encore
					aParams[aoInputs[iCount].name] = 'base64:' + base64PSencode(aoInputs[iCount].value);	// MODIF 2.4.3	// MODIF 2.5
				}
			}
		}
	}
	return aParams;
}

////////////////////////////////////////////////////////////////////////////////
// FONCTIONS DE PRESELECTION POUR LES WEBLIST       AJOUT V2.4.1
////////////////////////////////////////////////////////////////////////////////
var timer = null;
var chaine = "";
function startsWith (str1, str2) {
	var k = str1.substring(0, str2.length);
	return (str2.toLowerCase() == k.toLowerCase());
}
function liDown (list) {

	// Si pas IE on arrete car Firefox gère en standard :
	if (!document.all) return true;
	
	var c = event.keyCode;
	if (c < 48 && c!=32) return true;

	var s = String.fromCharCode(c);
	chaine += s;
	var n = list.selectedIndex;
	var ok = false;

	if (chaine.length > 1 && startsWith(list.options[n].text, chaine)) ok=true;

	for (var i=n+1; i < list.options.length && !ok; i++) {
		if (startsWith(list.options[i].text, chaine)) {
			n = i;
			ok = true;
		}
	}
	for (var i=0; i < n && !ok; i++) {
		if (startsWith(list.options[i].text,chaine)) {
			n = i;
			ok = true;
		}
	}
	list.selectedIndex = n;

	if (timer!=null) clearTimeout(timer);
	timer = setTimeout("clearChaine();",500);
	return false;
}
function clearChaine () {
	chaine="";
}


// AJOUT 2.4.3: Déplacement de toutes les fonctions Javascript des WebControls ici 
////////////////////// Fonctions liées au contrôle webMultiSelect //////////////////////
function __WebMultiSelect_syncValue(strID, bAutoPostBack, strOnChange) {
	var i;
	var s = "";
	var oValue = document.getElementById(strID);
	var oList = document.getElementById(strID + "_right");
	for (i=0; i < oList.length; i++) {
		if (i > 0) s += ",";
			s +=  oList.options[i].value;
	}
	oValue.value = s;
	
	// Mécanisme d'autopostback
	if (bAutoPostBack) throwPostBack(strID);

	// Le OnChange
	if (strOnChange) eval(strOnChange);
}
	
	
function __WebMultiSelect_add(strID, bAutoPostBack, strOnChange, iMax, strErrMsg) {
	__WebMultiSelect_move(document.getElementById(strID + "_left"), document.getElementById(strID + "_right"), iMax, strErrMsg);
	__WebMultiSelect_syncValue(strID, bAutoPostBack, strOnChange);
}
function __WebMultiSelect_remove(strID, bAutoPostBack, strOnChange) {
	__WebMultiSelect_move(document.getElementById(strID + "_right"), document.getElementById(strID + "_left"));
	__WebMultiSelect_syncValue(strID, bAutoPostBack, strOnChange);
}

function __WebMultiSelect_addAll(strID, bAutoPostBack, strOnChange, iMax, strErrMsg) {
	__WebMultiSelect_moveAll(document.getElementById(strID + "_left"), document.getElementById(strID + "_right"), iMax, strErrMsg);
	__WebMultiSelect_syncValue(strID, bAutoPostBack, strOnChange);
}

function __WebMultiSelect_removeAll(strID, bAutoPostBack, strOnChange) {
	__WebMultiSelect_moveAll(document.getElementById(strID + "_right"), document.getElementById(strID + "_left"));
	__WebMultiSelect_syncValue(strID, bAutoPostBack, strOnChange);
}

function __WebMultiSelect_pressup(strID, bAutoPostBack, strOnChange) {
	__WebMultiSelect_up(document.getElementById(strID + "_right"));
	__WebMultiSelect_syncValue(strID, bAutoPostBack, strOnChange);
}

function __WebMultiSelect_pressdown(strID, bAutoPostBack, strOnChange) {
	__WebMultiSelect_down(document.getElementById(strID + "_right"));
	__WebMultiSelect_syncValue(strID, bAutoPostBack, strOnChange);
}

// AJOUT 2.5.4: Alias du WebMultiSelect
function __wms_a(strID, bAutoPostBack, strOnChange, iMax, strErrMsg) {
	__WebMultiSelect_add(strID, bAutoPostBack, strOnChange, iMax, strErrMsg);
}
function __wms_r(strID, bAutoPostBack, strOnChange) {
	__WebMultiSelect_remove(strID, bAutoPostBack, strOnChange);
}

function __wms_aa(strID, bAutoPostBack, strOnChange, iMax, strErrMsg) {
	__WebMultiSelect_addAll(strID, bAutoPostBack, strOnChange, iMax, strErrMsg);
}

function __wms_ra(strID, bAutoPostBack, strOnChange) {
	__WebMultiSelect_removeAll(strID, bAutoPostBack, strOnChange);
}

function __wms_pu(strID, bAutoPostBack, strOnChange) {
	__WebMultiSelect_pressup(strID, bAutoPostBack, strOnChange);
}

function __wms_pd(strID, bAutoPostBack, strOnChange) {
	__WebMultiSelect_pressdown(strID, bAutoPostBack, strOnChange);
}


////////////////////// Fonctions liées au contrôle webTextArea //////////////////////
function __WebTextArea_CheckLen(obj, iMaxLength, bShowRemaining) {
	if (iMaxLength) {
		var iLength = obj.value.length;
				
		if (iLength > iMaxLength ) {
			obj.value = obj.value.substring(0, iMaxLength);
		}
	
		if (bShowRemaining) {
			// affichage du nombre de caractères restants
			var oRemain = document.getElementById(obj.id + "_remaining");
			if (iMaxLength - iLength >= 0) {
				oRemain.innerHTML = iMaxLength - iLength;
			}
		}
	}
}

////////////////////// Fonctions liées au contrôle webMLText //////////////////////
// Script d'affichage de la popup d'édition
function __WebMLText_openEditPopup(strID, strRootURL, strParams, iEBWidth, iEBHeight) {
	window.open(strRootURL + "psframeworkfo/webcontrols/resources/translator.php" + strParams,
	"translator",
	"scrollbars=yes,resizable=yes,width=" + iEBWidth + ",height=" + iEBHeight + ",left=100,top=100,modal=yes");
}


////////////////////// Fonctions liées au contrôle webCalendar //////////////////////
function __WebCalendar_reset(strID, strDefault) {
	var oTxt=document.getElementById(strID);
	oTxt.value = strDefault;
}


// Fonctions de gestion des dates
// DEPLACEMENT 2.5.4
function getDay(strDate) {
	return __getDay(strDate, _dt_sep, _dt_f_j);
}
function getMonth(strDate) {
	return __getMonth(strDate, _dt_sep, _dt_f_m);
}
function getYear(strDate) {
	return __getYear(strDate, _dt_sep, _dt_f_a);
}

// Fonction de vérification d'une date
// DEPLACEMENT 2.5.4
function verifDate(date) {
        if (date == _dt_wc_df){
    		return true;
    	}
    	
		var array=date.split(_dt_sep);
    	if (array.length!=3){
    		return false;
    	}

        var j,m,a,d2,maxj;
    	j=parseInt(array[_dt_f_j],10);
    	m=parseInt(array[_dt_f_m],10);
    	if (m<1 || m>12){
    		return false;
    	}
        
        //On met l'année sur 4chiffres ou 2 chiffres tous depends de DATE_FORMAT
        if (array[_dt_f_a].length < _dt_nb_y ){
    		a = 2000 + parseInt(array[2],10);
    	}
    	else if(array[_dt_f_a].length > _dt_nb_y){
    		return false;
    	}
    	else{
    		a = parseInt(array[_dt_f_a],10);
    	}
    	if (m==2){ //fevrier
    		if ((a % 4) == 0) {
    			if (j>29){
    				return false;
    			}
    		}
    		else{
    			if (j>28){
    				return false;
    			}
    		}
    	}
    return true;
}


// Ajout V2.5.2
function __getDay(strDate, strSeparateur, iJour) {
	var array=strDate.split(strSeparateur);
	//return parseInt(array[iJour],10);
	return array[iJour];
}

function __getMonth(strDate, strSeparateur, iMois) {
	var array=strDate.split(strSeparateur);
	//return parseInt(array[iMois],10);
	return array[iMois];
}

function __getYear(strDate, strSeparateur, iAnnee) {
	var array=strDate.split(strSeparateur);

    //On met l'année sur 4 chiffres ou 2 chiffres tous depends de DATE_FORMAT
    if (array[iAnnee].length<iAnnee){
		return 2000+parseInt(array[2],10);
	}
	else{
		//return parseInt(array[iAnnee],10);
		return array[iAnnee];
	}
}
// Fin Ajout V2.5.2

function __WebCalendar_onblur(obj, strErrDateInvalide, dtBloquerAvant, strErrDateAvant, dtBloquerApres, strErrDateApres, bVoirIntervale, strUniteIntervale) {    // Modif V2.5.2 // MODIF 2.5.3
	var oIntervale = '';

	// AJOUT 2.5.3
	if (bVoirIntervale) {
		oIntervale = document.getElementById(obj.id + '_itv');
	}
	
	if (!verifDate(obj.value) && obj.value!='') {
		alert(strErrDateInvalide);
		
		// AJOUT 2.5.3: Si date invalide alors pas d'age quoi qu'il arrive
		if (bVoirIntervale) {
			oIntervale.innerHTML = '';
		}
	}
	// Ajout V2.5.2
	// Vérification éventuelle de validité de la date
	else {
		iDate = ""+getYear(obj.value)+""+getMonth(obj.value)+""+getDay(obj.value)+"";	// DEPLACEMENT 2.5.3
	
	    if (dtBloquerAvant) {
			iDateBloquerAvant = ""+getYear(dtBloquerAvant)+""+getMonth(dtBloquerAvant)+""+getDay(dtBloquerAvant)+"";
			//alert('iDate = '+iDate+'\r\niDateBloquerAvant = '+iDateBloquerAvant);
			if (parseInt(iDate,10) < parseInt(iDateBloquerAvant,10)) {
				alert(strErrDateAvant);
				return false;
			}
		}
	    if (dtBloquerApres) {
			iDateBloquerApres = ""+getYear(dtBloquerApres)+""+getMonth(dtBloquerApres)+""+getDay(dtBloquerApres)+"";
			//alert('iDate = '+iDate+'\r\niDateBloquerApres = '+iDateBloquerApres);
			if (parseInt(iDate,10) > parseInt(iDateBloquerApres,10)) {
				alert(strErrDateApres);
				return false;
			}
		}
		
		// AJOUT 2.5.3
		// Calcul de l'intervale de temps à partir de la date
		if (bVoirIntervale) {
			// construit un objet date
			var dtDate = new Date(getYear(obj.value), getMonth(obj.value) - 1, getDay(obj.value));
			
			if (iDate) {
				// Récupère la valeur d'intervale
				var strIntervale = getServerRequest('WebCalendar::getIntervale', new Array(dtDate.getTime() / 1000, strUniteIntervale));
			}
			else {
				strIntervale = '';
			}
		
			oIntervale.innerHTML = strIntervale;
		}
	}
	// Fin Ajout V2.5.2
	
}

function __WebCalendar_showCalendar(strID, bAutoPostBack, strRootURL, dtBloquerAvant, dtBloquerApres) { // Modif V2.5.2
	var gimg = document.getElementById(strID + "_img");
	var ginpt = document.getElementById(strID);

	// On va parcourir toutes les frames de la page pour pouvoir initialiser la variable cW
	for(var i=0; i < window.frames.length; i++) {
		if (window.frames[i].name == strID + '_cal') {
			var cW=window.frames[i];
		}
	}

	var cF = document.getElementById(strID + "_cal");
	var htm = "/psframeworkfo/webcontrols/resources/dateselector.php";       //Modif V2.5.2
	htm += "?date=" + ginpt.value + "&dsel=" + ginpt.value + "&caller=" + strID;
	htm += "&dtBloquerAvant=" + dtBloquerAvant + "&dtBloquerApres=" + dtBloquerApres;    // Ajout V2.5.2
	if (bAutoPostBack) {
		htm += "&apb=true";
	}
	cW.document.body.innerHTML= "";
	cW.location.href=htm;
	__WebCalendar_position1(strID, gimg, cF);
	cF.style.display="block";
}

function __WebCalendar_position1(strID, img, cF) {
	var dB=document.body;
	if (img.offsetTop - dB.scrollTop < cF.style.pixelHeight) {
		cF.style.top = img.offsetTop + img.offsetHeight;
	} else {
		cF.style.top = img.offsetTop - cF.style.pixelHeight;
	}
	cF.style.left=img.offsetLeft;
}

// AJOUT 2.5.2: Calendar avec une div
function __WebCalendar_showCalendardiv(strID, strDefault) {
	var oDiv = document.getElementById(strID + '_cal');
	
	if (oDiv) {
		strDivContent = getServerRequest('WebCalendar::getPageHTML', new Array(strID, strDefault));
		oDiv.innerHTML = strDivContent;
		oDiv.style.display = 'block';
	}
}


//// Fonction  addAnEvent ////
// Ajoute dynamiquement un événement à un élément 
////////////////////////////
function addAnEvent( target, eventName, functionName) {
    // apply the method to IE
    if ( browser.isIE ) {
        //attachEvent dont work properly with this
        eval('target.on'+eventName+'=functionName');
    }
    // apply the method to DOM compliant browsers
    else {
        target.addEventListener( eventName , functionName , true ); // true is important for Opera7
    }
}

//// Fonction  __WebPopup_dragdrop ////
// Initialisation du drag&drop pour une webpopup 
////////////////////////////
function __WebPopup_dragdrop(iID) {
	Drag.init(document.getElementById(iID + '_handle'), document.getElementById(iID + '_div'));
}

//// Fonction  popupCourrier ////
// Gestion de la popup courrier
// - strActionParam = ID passé en action param si on n'affiche pas la popup
////////////////////////////
function popupCourrier(iIDAffectation, iIDCandidat, iIDPoste, strAction, strConfirm, strActionParam) {

	// Utilise un appel AJAX pour savoir s'il faut afficher la popup
	var strPopup;
	var bPopup;
	
	// Quoi qu'il arrive, fenêtre prioritaire. On considère donc que _bWorking est à false
	stopWorking();
	strPopup = getServerRequest('WorkflowCandidat::getAffichePopupCourrier', new Array(iIDAffectation, strAction));
	
	// AJOUT 2.5.3: Suppression d'un éventuel retour chariot
	strPopup = strPopup.replace('\n', '');
	strPopup = strPopup.replace('\r', '');
	strPopup = strPopup.replace('\r\n', '');
	strPopup = strPopup.replace(String.fromCharCode(32), '');
	
	// Si la longueur de la chaine est inférieure à 8 caractères, c'est qu'elle ne contient pas un chemin XML
	// qui doit contenir au moins "/popups/"
	if (strPopup.length > 8) {	
		bPopup = true;
	}
	else {
		bPopup = false;
	}

	if (bPopup) {
		showDivPopup('divPopup', 'PopupWorkflowCandidat::show', new Array('divPopup','0','id=' + iIDAffectation + '&iIDCandidat=' + iIDCandidat + '&iIDPoste=' + iIDPoste + '&action=' + strAction), 'center');
	}
	else {
		var bOK;
		if (strConfirm) {
			bOK = confirm(strConfirm);
		}
		else {
			bOK = true;
		}
		if (bOK) {
			ta(strAction, strActionParam);
		}
	}
}

//// Fonction  __frm_s_t ////
// Bascule une section de formulaire 
////////////////////////////
function __frm_s_t(strID, oImg, strDisplay) {
	// Récupère la section
	var oElem = document.getElementById(strID);
	// Récupère le champ caché
	var oHid = document.getElementById(strID + '_h');
	
	if (strID) {
		if (oHid.value == 1) {
			if (strDisplay && navigator.appName == 'Netscape') {
				oElem.style.display = strDisplay;
			}
			else {
				oElem.style.display = 'block';
			}
			oImg.src="/layout/images/ico_moins.gif"
			oHid.value = 0;
		}
		else {
			oElem.style.display = 'none';
			oImg.src="/layout/images/ico_plus.gif"
			oHid.value = 1;
		}
	}
}

//// Fonction  ifb ////
// Affiche ou masque une infobulle d'image 
////////////////////////////
function ifb(oTable, bHide) {
	// S'il n'est pas déjà affecté, affecte tout le suite le onmouseout
	if (! oTable.eventsok) {
		oTable.onmouseout = function(event) {
			ifb(this, true);
		}
		oTable.eventsok;
	}

	// Cherche les éléments de type image dans cette table
	aoImages = oTable.getElementsByTagName('img');
	for (iImg = 0; iImg < aoImages.length; iImg ++ ) {
		if (aoImages[iImg].className == 'ifb') {
			// Affecte le style	
			if (bHide) {
				aoImages[iImg].style.visibility = "hidden";
			}
			else {
				aoImages[iImg].style.visibility = "visible";
			}			
		}
	}
	
}

// AJOUT 2.5.4
var getElementsByClassName = function (className, tag, elm){
	if (document.getElementsByClassName) {
		getElementsByClassName = function (className, tag, elm) {
			elm = elm || document;
			var elements = elm.getElementsByClassName(className),
				nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
				returnElements = [],
				current;
			for(var i=0, il=elements.length; i<il; i+=1){
				current = elements[i];
				if(!nodeName || nodeName.test(current.nodeName)) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	else if (document.evaluate) {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
			for(var j=0, jl=classes.length; j<jl; j+=1){
				classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
			}
			try	{
				elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
			}
			catch (e) {
				elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
			}
			while ((node = elements.iterateNext())) {
				returnElements.push(node);
			}
			return returnElements;
		};
	}
	else {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = [],
				elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
				current,
				returnElements = [],
				match;
			for(var k=0, kl=classes.length; k<kl; k+=1){
				classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
			}
			for(var l=0, ll=elements.length; l<ll; l+=1){
				current = elements[l];
				match = false;
				for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
					match = classesToCheck[m].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	return getElementsByClassName(className, tag, elm);
};

// AJOUT 2.5.4
// Initialisation complète d'un WebValueCheckList
function wvcl_init(strID) {
	// Retrouve la table principale
	var oTbl = document.getElementById(strID + '_t');
	if (!oTbl) return false;
	
	// Boucle sur les TBODY
	var aTBodies = oTbl.getElementsByTagName('tbody');
	var oGroupTBody = null;
	for (var iBody = 0; iBody < aTBodies.length;   iBody ++) {
		if (aTBodies[iBody].className == 'gr') {
			oGroupTBody = aTBodies[iBody];
		}
		else if(aTBodies[iBody].className == 'li') {
			wvcl_initSection(aTBodies[iBody], oGroupTBody);
		}
	}
}

// Initialise une section d'un WebValueCheckList
function wvcl_initSection(oTBody, oGroupTBody) {
	// Mise à jour des états d'activation
	wvcl_update(oTBody, oGroupTBody)

	// Place les événements sur les input
	var aInputs = oTBody.getElementsByTagName('input');
	for (var iInput = 0; iInput < aInputs.length;   iInput ++) {
		if (aInputs[iInput].type == 'checkbox') {
			aInputs[iInput].onclick = function (event) {
				wvcl_update(oTBody, oGroupTBody);
			}
		}
	}
	
	// Place les événements sur les image
	var aImg = oGroupTBody.getElementsByTagName('img');
	for (var iImg = 0; iImg < aImg.length; iImg ++) {
		if (aImg[iImg].className == 'all') {
			aImg[iImg].onclick = function (event) {
				wvcl_ca(oTBody, oGroupTBody, false);
			}
		}
		else if (aImg[iImg].className == 'none') {
			aImg[iImg].onclick = function (event) {
				wvcl_ca(oTBody, oGroupTBody, true);
			}
		}
		else if (aImg[iImg].className == 'mix') {
			aImg[iImg].onclick = function (event) {
				wvcl_ca(oTBody, oGroupTBody, true);
			}
		}
	}
}

// AJOUT 2.5.4
// Met à jour la case à cocher du groupe quand la valeur d'une case a changé
function wvcl_update(oTBody, oGroupTBody) {
	var iNbCheck = 0;
	var iNbUnCheck = 0;
	// Boucle sur les input pour récupérer leur état d'activation
	var aInputs = oTBody.getElementsByTagName('input');
	for (var iInput = 0; iInput < aInputs.length;   iInput ++) {
		if (aInputs[iInput].type == 'checkbox') {
			if (aInputs[iInput].checked) {
				iNbCheck ++;
			}
			else {
				iNbUnCheck ++;
			}
		}
	}
	
	// Récupère les images du tbody du groupe
	var oImgAll = null;
	var oImgNone = null;
	var oImgMix = null;
	
	var aImg = oGroupTBody.getElementsByTagName('img');
	for (var iImg = 0; iImg < aImg.length; iImg ++) {
		if (aImg[iImg].className == 'all') {
			oImgAll = aImg[iImg];
		}
		if (aImg[iImg].className == 'none') {
			oImgNone = aImg[iImg];
		}
		if (aImg[iImg].className == 'mix') {
			oImgMix = aImg[iImg];
		}
	}
	
	// Case à cocher différente selon les cas
	if (iNbUnCheck == 0) {
		// Toutes les cases cochées
		oImgAll.style.display = 'inline';
		oImgNone.style.display = 'none';
		oImgMix.style.display = 'none';
	}
	else if(iNbCheck == 0) {
		// Aucune case cochée
		oImgAll.style.display = 'none';
		oImgNone.style.display = 'inline';
		oImgMix.style.display = 'none';
	}
	else {
		// Certaines cases cochées mais pas toutes
		oImgAll.style.display = 'none';
		oImgNone.style.display = 'none';
		oImgMix.style.display = 'inline';
	}

}

// AJOUT 2.5.4
// Code lié au WebValueCheckList (cochage multiple)
function wvcl_ca(oTBody, oGroupTBody, bCheck) {
	var aInputs = oTBody.getElementsByTagName('input');
	for (var iInput = 0; iInput < aInputs.length;   iInput ++) {
		if (aInputs[iInput].type == 'checkbox') {
			aInputs[iInput].checked = bCheck;
		}
	}
	wvcl_update(oTBody, oGroupTBody);
}


// AJOUT 2.5.5: Gestion côté client du htmlspecialchars
function htmlspecialchars (string, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Mirek Slugen
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Nathan
    // +   bugfixed by: Arno
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +    bugfixed by: Brett Zamir (http://brett-zamir.me)
    // -    depends on: get_html_translation_table
    // *     example 1: htmlspecialchars("<a href='test'>Test</a>", 'ENT_QUOTES');
    // *     returns 1: '&lt;a href=&#039;test&#039;&gt;Test&lt;/a&gt;'

    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();

    if (false === (histogram = this.get_html_translation_table('HTML_SPECIALCHARS', quote_style))) {
        return false;
    }

    histogram["'"] = '&#039;';
    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(symbol).join(entity);
    }

    return tmp_str;
}

function htmlspecialchars_decode(string, quote_style) {
    // Convert special HTML entities back to characters
    //
    // version: 906.401
    // discuss at: http://phpjs.org/functions/htmlspecialchars_decode
    // +   original by: Mirek Slugen
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Mateusz "loonquawl" Zalega
    // +      input by: ReverseSyntax
    // +      input by: Slawomir Kaniecki
    // +      input by: Scott Cariss
    // +      input by: Francois
    // +   bugfixed by: Onno Marsman
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +    bugfixed by: Brett Zamir (http://brett-zamir.me)
    // -    depends on: get_html_translation_table
    // *     example 1: htmlspecialchars_decode("<p>this -&gt; &quot;</p>", 'ENT_NOQUOTES');
    // *     returns 1: '<p>this -> &quot;</p>'
    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();

    if (false === (histogram = this.get_html_translation_table('HTML_SPECIALCHARS', quote_style))) {
        return false;
    }

    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(entity).join(symbol);
    }
    tmp_str = tmp_str.split('&#039;').join("'");

    return tmp_str;
}

function get_html_translation_table(table, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: noname
    // +   bugfixed by: Alex
    // +   bugfixed by: Marco
    // +   bugfixed by: madipta
    // +   improved by: KELAN
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +    bugfixed by: Brett Zamir (http://brett-zamir.me)
    // %          note: It has been decided that we're not going to add global
    // %          note: dependencies to php.js. Meaning the constants are not
    // %          note: real constants, but strings instead. integers are also supported if someone
    // %          note: chooses to create the constants themselves.
    // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
    // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}

    var entities = {}, histogram = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};

    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';

    useTable       = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS';
    useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT';

    if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') {
        throw new Error("Table: "+useTable+' not supported');
        // return false;
    }

    if (useTable === 'HTML_ENTITIES') {
        entities['160'] = '&nbsp;';
        entities['161'] = '&iexcl;';
        entities['162'] = '&cent;';
        entities['163'] = '&pound;';
        entities['164'] = '&curren;';
        entities['165'] = '&yen;';
        entities['166'] = '&brvbar;';
        entities['167'] = '&sect;';
        entities['168'] = '&uml;';
        entities['169'] = '&copy;';
        entities['170'] = '&ordf;';
        entities['171'] = '&laquo;';
        entities['172'] = '&not;';
        entities['173'] = '&shy;';
        entities['174'] = '&reg;';
        entities['175'] = '&macr;';
        entities['176'] = '&deg;';
        entities['177'] = '&plusmn;';
        entities['178'] = '&sup2;';
        entities['179'] = '&sup3;';
        entities['180'] = '&acute;';
        entities['181'] = '&micro;';
        entities['182'] = '&para;';
        entities['183'] = '&middot;';
        entities['184'] = '&cedil;';
        entities['185'] = '&sup1;';
        entities['186'] = '&ordm;';
        entities['187'] = '&raquo;';
        entities['188'] = '&frac14;';
        entities['189'] = '&frac12;';
        entities['190'] = '&frac34;';
        entities['191'] = '&iquest;';
        entities['192'] = '&Agrave;';
        entities['193'] = '&Aacute;';
        entities['194'] = '&Acirc;';
        entities['195'] = '&Atilde;';
        entities['196'] = '&Auml;';
        entities['197'] = '&Aring;';
        entities['198'] = '&AElig;';
        entities['199'] = '&Ccedil;';
        entities['200'] = '&Egrave;';
        entities['201'] = '&Eacute;';
        entities['202'] = '&Ecirc;';
        entities['203'] = '&Euml;';
        entities['204'] = '&Igrave;';
        entities['205'] = '&Iacute;';
        entities['206'] = '&Icirc;';
        entities['207'] = '&Iuml;';
        entities['208'] = '&ETH;';
        entities['209'] = '&Ntilde;';
        entities['210'] = '&Ograve;';
        entities['211'] = '&Oacute;';
        entities['212'] = '&Ocirc;';
        entities['213'] = '&Otilde;';
        entities['214'] = '&Ouml;';
        entities['215'] = '&times;';
        entities['216'] = '&Oslash;';
        entities['217'] = '&Ugrave;';
        entities['218'] = '&Uacute;';
        entities['219'] = '&Ucirc;';
        entities['220'] = '&Uuml;';
        entities['221'] = '&Yacute;';
        entities['222'] = '&THORN;';
        entities['223'] = '&szlig;';
        entities['224'] = '&agrave;';
        entities['225'] = '&aacute;';
        entities['226'] = '&acirc;';
        entities['227'] = '&atilde;';
        entities['228'] = '&auml;';
        entities['229'] = '&aring;';
        entities['230'] = '&aelig;';
        entities['231'] = '&ccedil;';
        entities['232'] = '&egrave;';
        entities['233'] = '&eacute;';
        entities['234'] = '&ecirc;';
        entities['235'] = '&euml;';
        entities['236'] = '&igrave;';
        entities['237'] = '&iacute;';
        entities['238'] = '&icirc;';
        entities['239'] = '&iuml;';
        entities['240'] = '&eth;';
        entities['241'] = '&ntilde;';
        entities['242'] = '&ograve;';
        entities['243'] = '&oacute;';
        entities['244'] = '&ocirc;';
        entities['245'] = '&otilde;';
        entities['246'] = '&ouml;';
        entities['247'] = '&divide;';
        entities['248'] = '&oslash;';
        entities['249'] = '&ugrave;';
        entities['250'] = '&uacute;';
        entities['251'] = '&ucirc;';
        entities['252'] = '&uuml;';
        entities['253'] = '&yacute;';
        entities['254'] = '&thorn;';
        entities['255'] = '&yuml;';
    }

    if (useQuoteStyle !== 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }
    if (useQuoteStyle === 'ENT_QUOTES') {
        entities['39'] = '&#39;';
    }
    entities['60'] = '&lt;';
    entities['62'] = '&gt;';

    // ascii decimals for better compatibility
    entities['38'] = '&amp;';

    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal);
        histogram[symbol] = entities[decimal];
    }

    return histogram;
}
/**************************************************
 * dom-drag.js
 * 09.25.2001
 * www.youngpup.net
 **************************************************
 * 10.28.2001 - fixed minor bug where events
 * sometimes fired off the handle, not the root.
 **************************************************/

var Drag = {

    obj : null,

    init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper)
    {
        o.onmousedown    = Drag.start;

        o.hmode            = bSwapHorzRef ? false : true ;
        o.vmode            = bSwapVertRef ? false : true ;

        o.root = oRoot && oRoot != null ? oRoot : o ;

        if (o.hmode  && isNaN(parseInt(o.root.style.left  ))) o.root.style.left   = "0px";
        if (o.vmode  && isNaN(parseInt(o.root.style.top   ))) o.root.style.top    = "0px";
        if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right  = "0px";
        if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px";

        o.minX    = typeof minX != 'undefined' ? minX : null;
        o.minY    = typeof minY != 'undefined' ? minY : null;
        o.maxX    = typeof maxX != 'undefined' ? maxX : null;
        o.maxY    = typeof maxY != 'undefined' ? maxY : null;

        o.xMapper = fXMapper ? fXMapper : null;
        o.yMapper = fYMapper ? fYMapper : null;

        o.root.onDragStart    = new Function();
        o.root.onDragEnd    = new Function();
        o.root.onDrag        = new Function();
    },

    start : function(e)
    {
        var o = Drag.obj = this;
        e = Drag.fixE(e);
        var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
        var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
        o.root.onDragStart(x, y);

        o.lastMouseX    = e.clientX;
        o.lastMouseY    = e.clientY;

        if (o.hmode) {
            if (o.minX != null)    o.minMouseX    = e.clientX - x + o.minX;
            if (o.maxX != null)    o.maxMouseX    = o.minMouseX + o.maxX - o.minX;
        } else {
            if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
            if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
        }

        if (o.vmode) {
            if (o.minY != null)    o.minMouseY    = e.clientY - y + o.minY;
            if (o.maxY != null)    o.maxMouseY    = o.minMouseY + o.maxY - o.minY;
        } else {
            if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y;
            if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y;
        }

        document.onmousemove    = Drag.drag;
        document.onmouseup        = Drag.end;

        return false;
    },

    drag : function(e)
    {
        e = Drag.fixE(e);
        var o = Drag.obj;

        var ey    = e.clientY;
        var ex    = e.clientX;
        var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
        var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
        var nx, ny;

        if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
        if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
        if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
        if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);

        nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
        ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));

        if (o.xMapper)        nx = o.xMapper(y)
        else if (o.yMapper)    ny = o.yMapper(x)

        Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
        Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
        Drag.obj.lastMouseX    = ex;
        Drag.obj.lastMouseY    = ey;

        Drag.obj.root.onDrag(nx, ny);
        return false;
    },

    end : function()
    {
        document.onmousemove = null;
        document.onmouseup   = null;
        Drag.obj.root.onDragEnd(    parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), 
                                    parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]));
        Drag.obj = null;
    },

    fixE : function(e)
    {
        if (typeof e == 'undefined') e = window.event;
        if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
        if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
        return e;
    }
};
/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/

var Base64 = {

	// private property
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

	// public method for encoding
	encode : function (input) {
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0;

		input = Base64._utf8_encode(input);

		while (i < input.length) {

			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);

			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;

			if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			} else if (isNaN(chr3)) {
				enc4 = 64;
			}

			output = output +
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

		}

		return output;
	},

	// public method for decoding
	decode : function (input) {
		var output = "";
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;

		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

		while (i < input.length) {

			enc1 = this._keyStr.indexOf(input.charAt(i++));
			enc2 = this._keyStr.indexOf(input.charAt(i++));
			enc3 = this._keyStr.indexOf(input.charAt(i++));
			enc4 = this._keyStr.indexOf(input.charAt(i++));

			chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;

			output = output + String.fromCharCode(chr1);

			if (enc3 != 64) {
				output = output + String.fromCharCode(chr2);
			}
			if (enc4 != 64) {
				output = output + String.fromCharCode(chr3);
			}

		}

		output = Base64._utf8_decode(output);

		return output;

	},

	// private method for UTF-8 encoding
	_utf8_encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	},

	// private method for UTF-8 decoding
	_utf8_decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;

		while ( i < utftext.length ) {

			c = utftext.charCodeAt(i);

			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}

		}

		return string;
	}

}//////////////////////////////////////////////////////////////////////////////////////////
/// AJOUT 2.5.3: Remise à plat des fonctionnalités AJAX
///		- Tentative d'homogénéisation des fonctions
///		- Passage des valeurs en POST pour éviter limitations de taille d'URL
///		- Utilisation de requêtes asynchrones
//////////////////////////////////////////////////////////////////////////////////////////

// Fonction getServerRequest
// Conservée par compatibilité avec l'existant (fonction du pagejs)
// Le paramètre strHTTPMethod n'est pas pris en compte (on passe maintenant tout en POST)
function getServerRequest(strMethod, astrParams, strHTTPMethod) {
	return ajax_syncMethod(strMethod, astrParams);
}

// Fonction ajax_prepareContexte
// Renvoie un paramètre à ajouter au tableau de paramètres, contenant tout le contexte de page pour un appel AJAX
function ajax_prepareContexte() {
	// Ajoute le contexte de page
	var strVals = '';
	for (i = 0; i < _aCtrls.length; i++) {
		var strIDCtrl = _aCtrls[i];
		var oCtrl = document.getElementById(strIDCtrl);
		if (oCtrl) {
			if (strVals) strVals += "&";
			strVals += strIDCtrl + "=" + oCtrl.value;
		} 			
	}

	for (i = 0; i < _aParams.length; i++) {
		var strParam = _aParams[i];
		var aCtrl = document.getElementsByName("__PageParam__" + strParam);
		if (aCtrl.length > 1) {
			for (iCtrl = 0; iCtrl < aCtrl.length; iCtrl ++) {
				var oCtrl = aCtrl[iCtrl];
				if (oCtrl) {
					if (strVals) strVals += "&";
					strVals += "__PageParam__" + strParam + "[]=" + oCtrl.value;
				}
			} 			
		}
		else {
			var oCtrl = aCtrl[0];
			if (oCtrl) {
				if (strVals) strVals += "&";
				strVals += "__PageParam__" + strParam + "=" + oCtrl.value;
			} 			
		}
	}
	
	// Ajoute aussi la liste des paramètres de page
	if (strVals) strVals += "&";
	strVals += "__ParamsList" + "=" + document.getElementById("__ParamsList").value;
	
	// Renvoie le paramètre à ajouter au tableau
	return '__ajax:' + base64PSencode(strVals);
}


// Fonction ajax_prepareData
// Met en forme le tableau de paramètre pour le passer à la requête AJAX
function ajax_prepareData(astrParams) {
	// Ajout des paramètres
	var strParams = '';
	if (astrParams) {
		if (astrParams.toString()) {
			if (astrParams.toString().split(",")) {
			 	for(var i = 0; i < astrParams.toString().split(",").length; i++) {
			 		if (astrParams[i]) {
				 		// On regarde si c'est déjà encodé, si c'est le cas on n'encode pas
						if (strParams) strParams += '&';      
				 		
				 		if (astrParams[i].toString().indexOf("%") != -1) {
				 			strParams += 'params[]=' + astrParams[i];
						}
						else {
							strParams += 'params[]=' + escape(astrParams[i]);
						}
					}
					// Si la valeur du paramètre est zéro :
					else {
						if (strParams) strParams += '&';      
						strParams += 'params[]=0';
					}
				}
			}
		}
	}
	return strParams;
}

// Fonction getAjaxRequest
// Conservée par compatibilité avec l'existant (fonction du pagejs)
// Passe une requête en rajoutant le contexte de page dans les paramètres
function ajax_asyncRequestWithContext(strMethod, astrParams, strDivID) {
	strURL = _strJSI + '&method=' + strMethod;

	// Ajoute un paramètre de contexte à la liste des paramètres
	astrParams[astrParams.length] = ajax_prepareContexte();

	// Prépare les paramètres	
	strParams = ajax_prepareData(astrParams);

	// Exécute la requête avec un HTTP Request asynchrone
	ajax_asyncRequest(strURL, strParams, strDivID);
}


// Fonction ajax_asyncRequest
// Envoie une requête ajax asynchrone et renvoie la réponse dans la div dont l'ID est spécifiée
// Les données doivent être URLEncodées
function ajax_asyncRequest(strURL, strData, strDivID, oContainer) {
	var xmlDoc = null;
	
	// Sélection navigateur
 	if (typeof window.ActiveXObject != 'undefined' ) {
		xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
	}
	else {
		xmlDoc = new XMLHttpRequest();
	}

	xmlDoc.open("POST", strURL, true);	// Asynchrone
	
	// Fonction de callback dynamique
	xmlDoc.onreadystatechange = function() {
	    if (xmlDoc.readyState != 4) { return; }

	    // AJOUT 2.5.4: Si on a précisé un container (infobulle par exemple) alors on remplit et on resize
	    if (strDivID) {
		    var oDiv = document.getElementById(strDivID);
		    oDiv.innerHTML = xmlDoc.responseText;
		}
		else {
	    	oContainer.fill(xmlDoc.responseText);
	    	oContainer.move();
		}
	};
	
	// En-tête pour les données envoyées en POST au format URLEncodé		
	xmlDoc.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=utf-8");
	
	// Envoie la requête
	xmlDoc.send(strData);
}


// Fonction ajax_asyncRequest
// Envoie une requête ajax synchrone
function ajax_syncRequest(strURL, strData) {
	if (! _bWorking) {
		startWorking();
		
		var xmlDoc = null;
		//if (!strMethod) strMethod = "GET";		// MODIF 2.4.3
	
	 	if (typeof window.ActiveXObject != 'undefined' ) {
			xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
		}
		else {
			xmlDoc = new XMLHttpRequest();
		}

		xmlDoc.open("POST", strURL, false);
		xmlDoc.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=utf-8");
		xmlDoc.send(strData);
		
		stopWorking();
	
		if ( xmlDoc.readyState != 4 ) return ;
		
	    return xmlDoc.responseText;
	}
}


// Fonction ajax_asyncMethod
// Appel asynchrone d'une méthode en ajax
function ajax_asyncMethod(strMethod, astrParams, strDivID, oContainer) {
	strURL = _strJSI + '&method=' + strMethod;

	// Prépare les paramètres	
	strParams = ajax_prepareData(astrParams);

	// Exécute la requête avec un HTTP Request
	strResult = ajax_asyncRequest(strURL, strParams, strDivID, oContainer);
}

// Fonction ajax_syncMethod
// Appel synchrone d'une méthode en ajax
function ajax_syncMethod(strMethod, astrParams) {
	strURL = _strJSI + '&method=' + strMethod;

	// Prépare les paramètres
	strParams = ajax_prepareData(astrParams);

	// Exécute la requête avec un HTTP Request
	return ajax_syncRequest(strURL, strParams);
}

// Fonction ajax_getValue
// Code de récupération de la valeur instantanée côté client
function ajax_getValue(strID) {
	var oControl = document.getElementById(strID);
	
	// AJOUT 2.5.5: Gestion des radio buttons
	if (!oControl) {
	    // On est peut-être dans le cas de radio button. Ce sont en fait des input différents
		// Avec un même name mais des id différents
		// Du coup on tente de travailler avec le name
		var aControls = document.getElementsByName(strID);
		// Retourne une concaténation (avec des ,) de toutes les valeurs qui sont checked
		var strReturn = '';
		for (var iCtrl =0; iCtrl < aControls.length; iCtrl ++) {
			var oControl = aControls[iCtrl];
			if (oControl.checked) {
				if (strReturn) strReturn += ',';
				strReturn += oControl.value;
			}
		}
		return strReturn;
	}
	else {
		if (oControl.tagName == 'SELECT') {
			return oControl.options[oControl.options.selectedIndex].value;
		}
		else {
			return oControl.value;
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////////
/// AJOUT 2.5.4: Gestion propre des infobulles
//////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////
// Classe Infobulle
//	- Permet de stocker les propriétés d'une infobulle
//////////////////////////////////////////////////////////////////////////////////////////
var Infobulle = function(iIndex, strID, bLockable) {
	this.index = iIndex;		// Indice de création de l'infobulle
	this.id = strID;			// identifiant unique de l'infobulle
	this.visible = false;		// Visibilité
	this.filled = false;		// Remplie
	this.lockable = bLockable;	// Infobulle avec "punaise" ou pas
	this.locked = false;		// Infobulle locké ou pas
	this.positionAuto = true;	// Type de positionnement
	this.content = '';			// Contenu de l'infobulle
	this.timer = null;			// Timer de suppression
	this.parentIndex = null;	// Indice de l'infobulle parent
	this.childIndex = null;		// Indice de l'infobulle enfant
	
	// Parties composant l'infobulle
	this.html_div = null;
	this.html_att = null;
	this.html_tb = null;
	this.html_t = null;
	this.html_hdl = null;
	this.html_c = null;
	this.html_content = null;
	this.html_parent = null;	// Parent html (permet le "rattachement" de la div)
	
	// A la création de l'objet, on crée aussi la DIV elle même
	var strDiv = '';
	var strHTMLID = 'ifb' + this.index;

	// Crée le contenu de la div
	strDiv += '<div id="'+ strHTMLID + '_div" class="rpt_div">';
	strDiv += '<table><tr>';
	
	// contenu principal
	strDiv += '<td class="bord">';
	strDiv += '<table>';
	if (this.lockable) {
		// Barre avec punaise
		strDiv += '<tr id="'+ strHTMLID + '_tb">';
		strDiv += '<td></td>';
		strDiv += '<td align="right"><img id="'+ strHTMLID + '_t" src="/layout/images/ico_punaise.gif"></td>';
		strDiv += '<tr>';
		// Handle
		strDiv += '<tr id="'+ strHTMLID + '_hdl" class="handle" style="display:none;">';
		strDiv += '<td></td>';
		strDiv += '<td align="right"><img id="'+ strHTMLID + '_c" src="/layout/images/popup/ico_close_02.gif"></td>';
		strDiv += '<tr>';
	}
	// Contenu
	if (_bLog) strDiv += '<tr><td colspan="2">' + strHTMLID + '</td></tr>';
	
	strDiv += '<tr>';
	strDiv += '<td colspan="2" class="form_champ" id="' + strHTMLID + '_divcontent"><img src="/layout/images/wait2.gif"></td>';
	strDiv += '</tr>';
	strDiv += '</table>';
	strDiv += '</td>';
	
	// Pointillés d'attache
	strDiv += '<td class="att" id="'+ strHTMLID + '_att">&nbsp;</td>';
	strDiv += '</tr></table>';
	strDiv += '</div>';

	// Attachement du contenu au document
	var oDiv = document.createElement('div');
	oDiv.innerHTML = strDiv;	
	document.body.insertBefore(oDiv, null);
	
	// Récupère les divs utiles
	this.html_div = document.getElementById(strHTMLID + '_div');
	if (! this.html_div) return false;
	
	this.html_att = document.getElementById(strHTMLID + '_att');
	this.html_content = document.getElementById(strHTMLID + '_divcontent');
	if (this.lockable) {
		this.html_tb = document.getElementById(strHTMLID + '_tb');
		this.html_t = document.getElementById(strHTMLID + '_t');
		this.html_hdl = document.getElementById(strHTMLID + '_hdl');
		this.html_c = document.getElementById(strHTMLID + '_c');
	}
		
	// Div cachée par défaut
	this.html_div.style.visibility = "hidden";
	
	// Ajoute les événements liés
	this.addEvents();
	
}
// Méthode fill: Remplit à partir d'un contenu
Infobulle.prototype.fill = function(strContent) {
	this.html_content.innerHTML = strContent;
	this.filled = true;
	
	// Pour chaque élément du contenu de type image on ajoute l'index de l'ifb courante
	// Ca permettra de gérer la notion de père/fils
	var aElems = this.html_content.getElementsByTagName('img'); 
	
	for (iElem = 0; iElem < aElems.length; iElem ++ ) {
		aElems[iElem].index = this.index;
	}
}
// Méthode move: Positionne l'infobulle (éventuellement par rapport à l'élément parent fourni)
Infobulle.prototype.move = function() {
	// Attention, on positionne tant que ça bouge (limite = 5 fois)
	// En effet, le fait de déplacer peut changer le offsetWidth
	// Du coup il faut quelques itérations pour trouver la bonne position
	var iCount = 0;
	var iOldLeft = -1000;
	var iLeft = getLeft(this.html_parent) - this.html_div.offsetWidth;
	if (iLeft < 0) iLeft = 0;

	while(iLeft != iOldLeft && iCount < 5) {
		if (this.positionAuto) {
			this.html_div.style.left = iLeft;
			this.html_div.style.top = getTop(this.html_parent);
		}
		else {
			this.html_div.style.left = iLeft;
			this.html_div.style.top = getTop(this.html_parent) - this.html_div.offsetHeight;
		}
		iOldLeft = iLeft;
		iLeft = getLeft(this.html_parent) - this.html_div.offsetWidth;
		if (iLeft < 0) iLeft = 0;
		iCount ++;
	}
}
// Méthode show: Rend une infobulle visible
Infobulle.prototype.show = function() {
	this.visible = true;
	this.html_div.style.visibility = "visible";
}
// Méthode hide: Rend une infobulle invisible
Infobulle.prototype.hide = function() {
	// Si il y a un enfant, on maintient ouvert tant que l'enfant est visible
	if (this.childIndex) {
		oChild = g_ifbm.infobulles[this.childIndex];
		if (oChild && oChild.visible) return false;
	}

	// Si lockée alors on délocke
	if (this.locked) this.unlock();
	
	this.visible = false;
	this.html_div.style.visibility = "hidden";
	
	// Déplace hors de l'écran
	this.html_div.style.left = -1000;
	this.html_div.style.top = -1000;

	// Annule l'éventuel timer
	if (this.timer) clearTimeout(this.timer);
}
// Méthode lock: Convertit en infobulle fixe
Infobulle.prototype.lock = function() {
	this.html_att.style.display = 'none';
	this.html_tb.style.display = 'none';
			
	// correction bug IE sur prise en charge table-row
	if (navigator.appName == 'Netscape') {
		this.html_hdl.style.display = 'table-row';
	}
	else {
		this.html_hdl.style.display = 'block';
	}
	
	// Active le bouton de fermeture
	var oIfb = this;
	this.html_c.onclick = function(event) {oIfb.hide();}
	
	// Active le drag & drop
	Drag.init(this.html_hdl, this.html_div);

	// Note la popup comme étant lockée	
	this.locked = true;
}
// Méthode unlock: Convertit en infobulle mobile
Infobulle.prototype.unlock = function() {
	// correction bug IE sur prise en charge table-row
	if (navigator.appName == 'Netscape') {
		this.html_tb.style.display = 'table-row';
	}
	else {
		this.html_tb.style.display = 'block';
	}
	this.html_att.style.display = 'block';	
	this.html_hdl.style.display = 'none';
			
	// Note la popup comme étant délockée	
	this.locked = false;
}

// Méthode countDown: Commence un décompte de suppression
Infobulle.prototype.countDown = function() {
	if (this.timer) clearTimeout(this.timer);
	
	if (!this.locked) {
		this.timer = setTimeout('oIfb = g_ifbm.infobulles[' + this.index + ']; oIfb.hide()', 200);
	
		// S'il a un parent, met un countdown aussi sur le parent
		if (this.parentIndex) {
			oParent = g_ifbm.infobulles[this.parentIndex];
			if (oParent) {
				oParent.countDown();
			}
		}
	}		
}
// Méthode keepAlive: Annule la suppression
Infobulle.prototype.keepAlive = function() {
	if (this.timer) clearTimeout(this.timer);
}

// Méthode addEvents: Ajoute les gestionnaires d'événements automatiques
Infobulle.prototype.addEvents = function() {
	var oIfb = this;
	this.html_div.onmouseover = function(event) {oIfb.keepAlive();}
	this.html_div.onmouseout = function(event) {oIfb.countDown();}
	if (this.lockable) {
		this.html_tb.ondblclick = function(event) {oIfb.lock();}
		this.html_t.onclick = function(event) {oIfb.lock();}
	}
}


//////////////////////////////////////////////////////////////////////////////////////////
// Classe IfbManager
//	- Classe de gestion des infobulles de la page
//////////////////////////////////////////////////////////////////////////////////////////
var IfbManager = function() {
	this.infobulles = new Array();	// Tableau des infobulles
	this.nextIndex = 1;				// Prochain index disponible
}
// Méthode addIfb: Ajoute une infobulle
IfbManager.prototype.addIfb = function(oElem, strID, bLockable, bPositionAuto) {
	if (! _bLoaded) return;				// Si page non chargée, annule

	var oIfb = null;
	// Recherche si on n'a pas déjà une infobulle avec cet ID
	for(iIndex = 1; iIndex < this.infobulles.length; iIndex ++) {
		if (this.infobulles[iIndex].id == strID) {
			oIfb = this.infobulles[iIndex];
		}
	}

	// Si on a déjà l'infobulle, il faut juste la réactiver
	if (oIfb) {
		// Si vérouillé, on ne fait rien de plus!
		if (oIfb.locked) return oIfb;
		oIfb.visible = true;
	}
	// Dans le cas contraire il faut la créer
	else {
		var oIfb = new Infobulle(this.nextIndex, strID, bLockable);

		// Ajoute au tableau
		this.infobulles[this.nextIndex] = oIfb;
		this.nextIndex ++;
		
		if (!oIfb) return false;	// Si problème pendant la création, on laisse tomber

		// Positionne les propriétés
		oIfb.lockable = bLockable;
		oIfb.positionAuto = bPositionAuto;
		oIfb.html_parent = oElem;
		
		// On ajoute un gestionnaire onmouseout pour la fermeture de l'infobulle
		oElem.onmouseout = function(event) {
			oIfb.countDown(); 
		}
	}

	// Regarde si ifb père
	if (oElem.index) {
		oParent = this.infobulles[oElem.index];
		if (oParent) {
			oParent.childIndex = oIfb.index;
			oIfb.parentIndex = oParent.index;
		} 
	}

	// On affiche
	oIfb.show();

	// On positionne l'infobulle
	oIfb.move();
	
	// On supprime toutes les infobulles non lockées
	for(iIndex = 1; iIndex < this.infobulles.length; iIndex ++) {
		if (this.infobulles[iIndex].id != oIfb.id && ! this.infobulles[iIndex].locked) {
			this.infobulles[iIndex].hide();
		}
	}

	// On retourne l'index d'infobulle
	return oIfb.index;
}
// Méthode fillIfb: Remplit une infobulle (éventuellement de manière asynchrone)
IfbManager.prototype.fillIfb = function(iIndex, strMethod, astrParams, strContenu) {
	// Récupère l'infobulle
	var oIfb = this.infobulles[iIndex];
	// Teste si l'infobulle existe
	if (! oIfb) return false;
	// Teste si toujours visible
	if (! oIfb.visible) return false;
	// Teste si déjà remplie
	if (oIfb.filled) return false;
	
	// 2 cas de figure: contenu passé directement ou par appel ajaxasynchrone
	if (strContenu) {
		oIfb.fill(strContenu);

		// Déplace au bon endroit
		oIfb.move();
	}
	else if(strMethod && astrParams) {
		// Appel ajax asynchrone
		ajax_asyncMethod(strMethod, astrParams, '', oIfb);
		
		// Note tout de suite comme rempli pour éviter appels ajax multiples
		this.filled = true;
	}
}


// Crée un gestionnaire d'infobulles global
var g_ifbm = new IfbManager();
//////////////////////////////////////////////////////////////////////////////////////////
/// AJOUT 2.5.4: Scripts liés aux WebControls
//////////////////////////////////////////////////////////////////////////////////////////
// Ce fichier est destiné à gérer les javascripts liés aux WebControls après réécriture propre
// en javascript objet
// La classe WCManager permet de gérer tous les WebControls en lot
// Chaque WebControl ne doit appeler qu'une méthode qui lui rattache ensuite tous les appels js
 

//////////////////////////////////////////////////////////////////////////////////////////
// Classe WCManager
//	- Classe de gestion des webcontrols de la page
//////////////////////////////////////////////////////////////////////////////////////////
var WCManager = function() {
	this.controls = new Array();	// Tableau des infobulles
	this.nextIndex = 1;				// Prochain index disponible
}
// Méthode générique d'ajout d'un contrôle
WCManager.prototype.addControl = function(oCtrl, oElem) {
	if (!oCtrl) return false;

	// Ajoute au tableau
	this.controls[this.nextIndex] = oCtrl;
	oCtrl.index = this.nextIndex;
	this.nextIndex ++;

	// Initialise 
	oCtrl.init();
	
	// Attache les événements
	oCtrl.addEvents();
	
	// Place un flag pour ne pas initialiser 2 fois
	oElem.added = 1;
}
// Ajoute un WebUploadFlat
WCManager.prototype.addWebUploadFlat = function(oElem, strID, iMaxFileSize) {
	// On regarde si le traitement n'a pas déjà été fait
	if (oElem.added) return true; 
	
	// Crée un nouveau contrôle
	var oCtrl = new WebUploadFlat(strID);
	
	// Positionne les options
	oCtrl.maxFileSize = iMaxFileSize;
		
	// Ajout du contrôle au gestionnaire 
	this.addControl(oCtrl, oElem);
}
// Ajoute un WebSelector
WCManager.prototype.addWebSelector = function(oElem, strID, iSize, iWidth, bLineFeed, bAutoPostback, strOnChange, iNbElemMaxi, strErrNbElemMaxi) {
	// Si page non chargée, retente plus tard
	if (! _bLoaded) {
		setTimeout(function () { g_wcm.addWebSelector(oElem, strID, iSize, iWidth, bLineFeed, bAutoPostback, strOnChange, iNbElemMaxi, strErrNbElemMaxi) }, 200);
	}
	else {
		// On regarde si le traitement n'a pas déjà été fait
		if (oElem.added) return true; 
		
		// Crée un nouveau contrôle
		var oCtrl = new WebSelector(strID);
		
		// Positionne les options
		oCtrl.size = iSize;
		oCtrl.width = iWidth;
		oCtrl.lineFeed = bLineFeed;
		oCtrl.autoPostback = bAutoPostback;
		oCtrl.onChange = strOnChange;
		oCtrl.nbMax = iNbElemMaxi;
		oCtrl.errMax = strErrNbElemMaxi;
			
		// Ajout du contrôle au gestionnaire 
		this.addControl(oCtrl, oElem);
	}
}


//////////////////////////////////////////////////////////////////////////////////////////
// Classe WebUploadFlat
//////////////////////////////////////////////////////////////////////////////////////////
var WebUploadFlat = function(strID) {
	this.id = strID;			// identifiant unique
	this.index = -1;			// Indice de création
	this.maxFileSize = 0;		// Taille maximale
	
	// Parties HTML
	this.html_hid = null;		// Champ caché contenant le nom temporaire
	this.html_upl= null;		// imput file
	this.html_txt = null;		// Champ texte contenant le nom original
	this.html_mfs = null;		// Champ MAX_FILE_SIZE
}
// Initialisation du contrôle
WebUploadFlat.prototype.init = function() {
	// Charge les composants HTML
	this.html_hid = document.getElementById(this.id);
	this.html_upl = document.getElementById(this.id + '_upl');
	this.html_txt = document.getElementById(this.id + '_txt');
	this.html_mfs = document.getElementById(this.id + '_mfs');
	
	// Place les balises name
	this.html_hid.name = this.html_hid.id;
	this.html_upl.name = this.html_upl.id;
	this.html_txt.name = this.html_txt.id;
}
// Méthode addEvents: Ajoute les gestionnaires d'événements automatiques
WebUploadFlat.prototype.addEvents = function() {
	var oCtrl = this;
	
	// Déclenche un postback sur le onchange
	this.html_upl.onchange = function(event) {
		oCtrl.prepareForm();
		throwPostBack(oCtrl.id);
	}
}
// Méthode prepareForm: Prépare le formulaire à l'envoi
WebUploadFlat.prototype.prepareForm = function() {
	var oForm = document.getElementById('MainForm');
	
	// Ajoute l'encodage multipart
	oForm.encoding = "multipart/form-data";
	
	// Ajoute un champ MAX_FILE_SIZE
	var strMaxFileSize = '<input type="hidden" name="MAX_FILE_SIZE" value="' + this.maxFileSize + '" />';
	this.html_mfs.innerHTML = strMaxFileSize;	
}


//////////////////////////////////////////////////////////////////////////////////////////
// Classe WebSelector
//////////////////////////////////////////////////////////////////////////////////////////
var WebSelector = function(strID) {
	this.id = strID;			// identifiant unique
	this.index = -1;			// Indice de création
	this.size = 0;				// Taille de la liste
	this.width = 0;				// Largeur de la liste
	this.lineFeed = true;		// Affiche ou pas un retour à la ligne entre chaque élément
	this.autoPostback = false;	// Evénement appelé sur le onchange
	this.onChange = '';			// Evénement appelé sur le onchange
	this.nbMax = 0;				// Nb d'éléments maxi autorisés
	this.errMax = '';			// Message si dépassemetn du nombre d'éléments maxi
	this.filled = false;		// Remplie
	this.visible = false;		// Visibilité
	this.timer = null;			// Timer de suppression
	
	// Parties HTML
	this.html_hid = null;		// Champ caché
	this.html_tbl = null;		// Tableau principal
	this.html_div = null;		// Div d'infobulle de sélection
	this.html_sel = null;		// Div des éléments sélectionnés
	this.html_add = null;		// TD du bouton add
	this.html_rem = null;		// TD du bouton clear
	this.html_ico = null;		// Zone des icônes
	this.html_img_add = null;	// Image du bouton add
	this.html_img_rem = null;	// Image du bouton clear
	this.html_list = null;		// Liste de selection
	this.html_wait = null;		// Image d'attente
}
// Initialisation du contrôle
WebSelector.prototype.init = function() {
	// AJOUT 2.5.4: On regarde si la div de même id n'existe pas déjà.
	// Si c'est le cas on la récupère, sinon on en crée une
	var oDivExiste = document.getElementById(this.id + '_div');
	if (oDivExiste) {
	    var oDiv = oDivExiste.parentNode;
	}
	else {
		var oDiv = document.createElement('div');
	}

	// A la création de l'objet, on crée aussi la div de sélection
	var strDiv = '';
	strDiv += '<div id="' + this.id + '_div" class="wsel_sel">';
	strDiv += '<img src="/layout/images/wait2.gif" />';
	strDiv += '<select multiple id="' + this.id + '_left" style="display:none">';
	strDiv += '</select>';
	strDiv += '</div>';

	oDiv.innerHTML = strDiv;
	document.body.insertBefore(oDiv, null);
	
	// Charge les composants HTML
	this.html_hid = document.getElementById(this.id);
	this.html_tbl = document.getElementById(this.id + '_tbl');
	this.html_div = document.getElementById(this.id + '_div');
	this.html_list = document.getElementById(this.id + '_left');
	
	// Retrouve les td d'image et celle de classe "i" et celle de la classe sel
	var aTDs = this.html_tbl.getElementsByTagName('td');
	for (var iTD = 0; iTD < aTDs.length; iTD ++){
		if (aTDs[iTD].className == 'add') {
			this.html_add = aTDs[iTD];
		}
		else if (aTDs[iTD].className == 'rem') {
			this.html_rem = aTDs[iTD];
		}
		else if (aTDs[iTD].className == 'i') {
			this.html_ico = aTDs[iTD];
		}
		else if (aTDs[iTD].className == 'sel' || aTDs[iTD].className == 'sel lf') {
			this.html_sel = aTDs[iTD];
		}

		if (this.html_add && this.html_rem && this.html_ico && this.html_sel) break;
	}

	// Retrouve l'image d'attente
	var aImgs = this.html_div.getElementsByTagName('img');
	this.html_wait = aImgs[0];

	// Place les tags HTML sur les composants du contrôle
	if (this.width) this.html_sel.style.width = this.width;
	
	// Crée les images des boutons add et remove
	this.html_img_add = document.createElement('img');
	this.html_img_add.src = '/psframeworkfo/webcontrols/resources/images/ws_add.gif';
	this.html_add.appendChild(this.html_img_add);

	this.html_img_rem = document.createElement('img');
	this.html_img_rem.src = '/psframeworkfo/webcontrols/resources/images/ws_clear.gif';
	this.html_img_rem.style.cursor = 'pointer';
	this.html_rem.appendChild(this.html_img_rem);


	// Options sur le select
	this.html_list.size = this.size;
	this.html_list.style.width = this.width + 20 + 'px';
}

// Méthode addEvents: Ajoute les gestionnaires d'événements automatiques
WebSelector.prototype.addEvents = function() {
	var oCtrl = this;

	// Attache les remove sur les anchors de la liste des sélectionnés
	var aAnchors = this.html_sel.getElementsByTagName('A');
	for (var iAnchor = 0; iAnchor < aAnchors.length; iAnchor ++) {
		if (aAnchors[iAnchor].id) {
			// A l'intérieur du onclick, this fait référence à l'anchor
			aAnchors[iAnchor].onclick = function (event) {
				oCtrl.remove(this);	
			}
		}
	}
	
	// Evénement sur l'icône d'ajout
	this.html_img_add.onmouseover = function (event) {
		// Affiche
		oCtrl.show();
		
		// Positionne
		oCtrl.move();

		// Chargement AJAX
		if (! oCtrl.filled) {
			oCtrl.load();
		}
		
	}
	this.html_img_add.onmousemove = function (event) { oCtrl.keepAlive(); }

	// Evénement sur l'icône de clear
	this.html_img_rem.onclick = function (event) { oCtrl.clear(); }
	
	// Evénements de masquage de la div
	this.html_img_add.onmouseout = function (event) { oCtrl.countDown();}
	this.html_div.onmouseover = function (event) { oCtrl.keepAlive(); }
	this.html_div.onmouseout = function (event) { oCtrl.countDown(); }
	
	// Ajout d'un élément
	this.html_list.onclick = function (event) { this.focus(); oCtrl.add(); this.focus();}
	
	// AJOUTS 2.5.5: Gestion du clavier
	this.html_list.onkeypress = function (event) {
	    var iKey;
     	if (window.event) {
	        iKey = window.event.keyCode;
	    }
	    else if (event.which) {
	        iKey = event.which;
		}
		// Si touche entrée
		if (iKey == 13) {
		    // Récupère les éléments dans la sélection et les bascule
		    this.focus(); oCtrl.add(); this.focus();

		}
	}
	
	// AJOUT 2.5.5: Force le focus sur le survol
	this.html_list.onmouseover = function (event) { this.focus(); }
}

// Méthode add: Ajoute un élément à la sélection
WebSelector.prototype.add = function() {
	// Boucle sur les options pour trouver celles qui sont sélectionnées
	var aIndex = new Array();
	for (var iOption = 0; iOption < this.html_list.options.length; iOption ++) {
	    // Attention, l'indice effectif va changer donc il faut à chaque fois décaler de 1
	    if (this.html_list.options[iOption].selected) aIndex.push(iOption - aIndex.length);
	}

	// Ajout effectif
	for (var iOption = 0; iOption < aIndex.length; iOption ++) {
	    this._add(aIndex[iOption]);
	}

 	// Synchronise
	this.sync();
}

// Méthode add: Ajoute un élément à la sélection
// Méthode privée qui ne déclenche pas de synch
WebSelector.prototype._add = function(iOldIndex) {
	if (iOldIndex == -1) return;
	var oOption = this.html_list.options[iOldIndex];

	// Contrôle sur le nombre d'éléments sélectionnés
	if (this.nbMax > 0) {
		var aAnchors = this.html_sel.getElementsByTagName('A');

		if (aAnchors.length >= this.nbMax) {
			if (this.errMax != '') alert(this.errMax);
		    return false;
		}
	}
	// Supprime l'élément de la liste de sélection en gardant le niveau de scroll
	var iScroll = this.html_list.scrollTop;
	if (iOldIndex > 0) {
		if (this.html_list.options[iOldIndex - 1]) this.html_list.selectedIndex = iOldIndex - 1;
	}
	this.html_list.options[iOldIndex] = null;
	this.html_list.scrollTop = iScroll;

	// Crée le nouvel Anchor
	var oAnchor = document.createElement('A');
	oAnchor.id = this.id + '#' + oOption.value;
	oAnchor.appendChild(document.createTextNode(oOption.text)); // MODIF 2.5.5
	this.html_sel.insertBefore(oAnchor, null);

	// Ajoute l'événement lié
	var oCtrl = this;
	oAnchor.onclick = function(event) {
		// Ici this fait référence à l'anchor
		oCtrl.remove(this);
	}
}


// Méthode remove: Supprime un élément de la sélection (publique)
WebSelector.prototype.remove = function(oElem) {
	this._remove(oElem);

	// Synchronise
	this.sync();
}

// Méthode clear: Vide la sélection
WebSelector.prototype.clear = function() {
	var aAnchors = this.html_sel.getElementsByTagName('A');
	for (var iAnchor = aAnchors.length - 1; iAnchor >= 0; iAnchor --) {
		if (aAnchors[iAnchor].id) {
			this._remove(aAnchors[iAnchor]);	
		}
	}
	
	// Synchronise
	this.sync();
}

// Méthode _remove: Supprime un élément de la sélection
// Méthode privée qui ne déclenche pas de synch
WebSelector.prototype._remove = function(oElem) {
	// MODIF 2.5.5: Il faut charger la liste de droite pour supprimer, sinon les valeurs disparaissent
	// Attention, chargement synchrone: on doit être sûr d'aller au bout avant de faire la suppression
	if (! this.filled && ! this.autopostback) {
		var strOptions = ajax_syncMethod('WebSelector::getListeAjax', new Array(this.id), '', this);
		this.fill(strOptions);
	}
	
	var aID = oElem.id.split('#');
	var strIDCtrl = aID[0];
	var strValeurElem = aID[1];
	
	var strCaption = oElem.innerHTML;

	// Si la liste de sélection existe, on remet dans cette liste
	if (this.filled) {
		var oOption = new Option(htmlspecialchars_decode(strCaption), strValeurElem);   // MODIF 2.5.5
		oOption.title = htmlspecialchars_decode(strCaption);
		this.html_list.options[this.html_list.options.length]= oOption;
	}
	oElem.parentNode.removeChild(oElem);
}


// Méthode sync: Synchronise la valeur du champ caché
WebSelector.prototype.sync = function() {
	// Construit la liste des ID
	var aAnchors = this.html_sel.getElementsByTagName('A');
	var s = '';
	for (var iAnchor = 0; iAnchor < aAnchors.length; iAnchor ++) {
		if (aAnchors[iAnchor].id) {
			var strID = aAnchors[iAnchor].id;
			var aID = strID.split('#');
			var strValeur = aID[1];
			
			if (s) s += ',';
			s += strValeur;
		}
	}
	
	// Affecte la valeur au champ caché
	this.html_hid.value = s;

	// Mécanisme d'autopostback
	if (this.autoPostback) throwPostBack(this.id);

	// Le OnChange
	if (this.onChange) eval(this.onChange);
}

// Méthode fill: Remplit à partir d'un contenu
WebSelector.prototype.fill = function(strContent) {
	// Parse la chaîne qui est du type clé1>valeur1|clé2>valeur2|...
	var aOpt = strContent.split('|');
	for (var iOption = 0; iOption < aOpt.length; iOption++ ) {
		var aKeyVal = aOpt[iOption].split('~');
		
		if (aKeyVal[0] && aKeyVal[1]) {
			// Ajoute une option
			var oOption = new Option(aKeyVal[1], aKeyVal[0]);
			oOption.title = aKeyVal[1];
			this.html_list.options[this.html_list.options.length]= oOption;
		}
	}
	this.filled = true;

	// Masque l'image d'attente
	this.html_wait.style.display = 'none';

	// Affiche le select
	this.html_list.style.display = 'block';

	// Sélectionne le premier élément de la liste
	if (this.html_list.options.length > 0) {
		this.html_list.selectedIndex = 0;
		this.html_list.focus();
	}
}

// Méthode load: Charge le contenu
WebSelector.prototype.load = function() {
	ajax_asyncMethod('WebSelector::getListeAjax', new Array(this.id), '', this);
	// Note tout de suite comme rempli pour éviter appels ajax multiples
	this.filled = true;
}

// Méthode move: Positionne la div de sélection
WebSelector.prototype.move = function() {
	this.html_div.style.left = getLeft(this.html_add) + this.html_add.offsetWidth + 2;
	this.html_div.style.top = getTop(this.html_ico);
}
// Méthode show: Affiche la liste de sélection
WebSelector.prototype.show = function() {
	this.visible = true;
	this.html_div.style.visibility = 'visible';
}

// Méthode hide: Cache la liste de sélection
WebSelector.prototype.hide = function() {
	this.visible = false;
	this.html_div.style.visibility = 'hidden';
}
// Méthode countDown: Commence un décompte de masquage
WebSelector.prototype.countDown = function() {
	if (this.timer) clearTimeout(this.timer);
	this.timer = setTimeout('var oCtrl = g_wcm.controls[' + this.index + ']; oCtrl.hide()', 200);
}
// Méthode keepAlive: Annule le masquage
WebSelector.prototype.keepAlive = function() {
	if (this.timer) clearTimeout(this.timer);
}


//////////////////////////////////////////////////////////////////////////////////////////
// Crée un gestionnaire global
var g_wcm = new WCManager();
