App.Modul.Fo = 1

var Fos = {
	all: {},
	load: {},
	Sel: null,
	Old: null
}
var FoGen = function(btn, Pgm) {
	var F = ElemPVar(btn,'Fo');  if (!F.Fo)  return;    //alert(Fo.Nom+crr+Lout(F))
	if (Pgm)  F.Fo[Pgm]()
	return F.Fo
}
var getFo = function(btn) { var F = ElemPVar(btn,'Fo');  return F.Fo }


var FoClass = function(Div, Proto) {
	var Nom, O, po_Table, S, Me = this
	if (isStr(Div)) { Nom = Div;  Div = $E(Div) }else  Nom = Div.id
	if (!Div)  return
	Div.Fo = this;  Div.name = Nom
	this.Nom		= Nom
	this.Div		= Div
	this.all		= []
	this.Droit  = 9
	this.initie = false
  this.ssFos, this.Grid, this.Typfo
	if (Proto) {
		//if ((O=Proto.Table)) { po_Table = copyObj(O);  delete(Proto.Table) }
		if ((po_Table=Proto.Table))  delete(Proto.Table)
		for (var K in Proto)  this[K] = Proto[K]
	}
	Fos.all[Nom] = this

	$('xmp.infoTable',Div).each(function() { var S;  if (this.parentNode==Div) { po_Table = JSOND(LText(this)) } })
	$('xmp.infoFo',Div).each(function() { var S;  if (this.parentNode==Div && (S=LX(this,'Typ'))) { Me[S] = JSOND(LText(this)) } })
	$('xmp.infoFo',Div).each(function() {
		if (this.parentNode!=Div || LX(this,'Typ'))  return
		var JS = JSOND(LText(this));  if (isStr(JS))  alert(JS);  else  for (S in JS)  Me[S] = JS[S]
	})

	if (this.Table)
		this.TableAutoCre = false
	else{
		this.Table = new TableClass(Nom,po_Table)
		this.TableAutoCre = true
	}
	if (this.Table)  this.Table.Fo = this
	if ((S=LX(Div,'divAide')))  this.divAide = LID(S)
	if (!this.CtlClass)  this.CtlClass = CtlClass  // prototype différent

	this.InitFo()
	this.gereAffich()
	Me.LoadssFo()
	//setTimeout(function () { Me.LoadssFo() },10)
	if (hasClass(Div,'Grid')) { Me.Grid = new GridClass(Me) }
	//alert(this)
	this.finLoad()
	return this
}

FoClass.prototype.finLoad = function() {}

FoClass.prototype.InitFo = function(Div) {
	var Cto, Cs=[], Ctl, Nom, Os=[], O1, O2, O3, i, j, T, Ch, Tag, S
	if (!Div)  Div = this.Div;  else  Div = LID(Div);  if (!Div)  return
	if (Div.tagName=='FORM') {
		T = this.Div.elements;  for (i=0; i<T.length; i++)  Os.push(T[i])
	}else{
		O1 = LTagt(Div,'INPUT');  O2 = LTagt(Div,'SELECT');  O3 = LTagt(Div,'TEXTAREA')
		Os = O1.concat(O2,O3)
	}
	O1 = LTags(Div,'SPAN');
	for (i=0; i<O1.length; i++) { if (LX(O1[i],'bd'))  Os.push(O1[i]) }
	for (i=0; i<Os.length; i++) { O1 = Os[i];  if ((S=LX(O1,'name')))  Cs[S] = O1 }
	this.Ctrls = Cs

	T = this.Table
	for (i=0; i<Os.length; i++) {
		Ctl = Os[i]
		Tag = Ctl.tagName
		if ("BUTTON,FIELDSET,EMBED,OBJECT".indexOf(Tag)>=0 || (Ctl.type && Ctl.type=='button'))  continue
		Nom = LX(Ctl,'name');  if (!Nom)  continue
		if ((O1=ElemPClass(Ctl,'Fo')) && O1.name!=this.Nom)  continue
		if (T && !T.initie)  Ch = T.Add(Nom)
		Cto = this.Add(Nom, Ctl);  if (!Cto)  continue;   // éviter les ctl sans name ou id
		//this.all[Nom] = Cto
	}
	for (Nom in this.all) { Cto = this.all[Nom]; if (!Cto.Champ)  Cto.ValDef() }    // pour la prise en compte des meta au cas où le champ JS n'était pas encore rempli au ValDef de création
	if (this.TableAutoCre) {
		if ((Cto=this.all['_NomT']))	T.NomT = Cto.Val()
		if ((Cto=this.all['_NomC'])) { T.NomC = Cto.Val();  T.ChCle = T.all[T.NomC]; }
		if ((Cto=this.all['_TypCle']))	T.TypCle = Cto.Val()
		if ((Cto=this.all['ValCle']))		T.ValCle = Cto.Val()
	}
}

FoClass.prototype.LoadssFo = function() {
	var T, i, Nom, ssf, D, Vu
	if ((T=this.ssFo)) {
		this.ssFos = {}
		for (i in T) {
			Nom = T[i];  this.ssFos[Nom] = ssf = new FoClass(Nom, { foParent:this })
 			D = ElemPClass(ssf.Div,'Vue')
 			Vu = D.Vue;  if (!Vu.Fo)  Vu.Fo = ssf
		}
	}
}

FoClass.prototype.ReInit = function(siVal) {
	if (this.Table)  this.Table.ReInit(siVal)
	this.onReInit()
}

FoClass.prototype.onReInit = function() {
	var Fs, k, G
	if ((G=this.Grid))  G.LoadData()
	if ((Fs=this.ssFos))  for (k in Fs) { Fs[k].onReInit() }
}

FoClass.prototype.Destroy = function(Div, avecCh) {  // Détruit les Cto et Ctrl de la Div et en option les Ch
	var T, Ctl, Cto, Ch, i, S
	if (!Div)  Div = this.Div;  else  Div = LID(Div);  if (!Div)  return
	T = ListCtl(Div)
	for (i=0; i<T.length; i++) {
		Ctl = T[i]
		Cto=Ctl.Cto
		if (avecCh && (Ch=Cto.Champ)) {
			delete(this.Table.all[Ch.Nom])
		}
		if (Cto) { Cto.Destroy();  delete(this.all[Cto.id]) }
	}
}

FoClass.prototype.Add = function(Nom, Ctl) {
	var Cto, n
	Ctl = Ctl || Nom;  if (isStr(Ctl))  Ctl = LID(Ctl)
	if ((Cto=this.all[Nom]))  Cto.Init(Ctl);  else  Cto = new this.CtlClass(this, Nom, Ctl)
	return Cto
}

FoClass.prototype.Champ = function(Nom) {
	if (this.Table)  return this.Table.all[Nom]
}

FoClass.prototype.ValDef = function() {
	var Cto, Nom
	for (Nom in this.all) { Cto = this.all[Nom];  Cto.ValDef() }
}

FoClass.prototype.getCtl = function(Nom) {
	var Cto, Ctl, S, J
	if (typeof(Nom)=='string') {
		if ((O=this.all[Nom]))  Ctl = O.Ctrl;  else  Ctl = this.Ctrls[Nom]
	}else
		Ctl = Nom
	return Ctl
}

FoClass.prototype.gereAffich = function() {
	var Cto, Ctl, D, OL, sp, Nom, id
	for (Nom in this.all) {
		Cto  = this.all[Nom];  Ctl = Cto.Ctrl;
		//id = Ctl.id || Nom
		//if (!(OL=$('label[forhl|=lb'+id+']').get(0))) {
		//	D = Ctl.parentNode
		//	OL = LTags(D,'LABEL',0)
		//}
		//if (OL) alert(Lout(OL)+crr+Lout(Ctl))
		//Cto.Label = OL
		if ((OL=Cto.Label)) {
			sp = ElemIn(OL, "@C='Etoile'", true, 0);
			if (Cto.NonVide || Cto.NonZero) {
				if (!sp)  InsertHtml("<span class=Etoile>&nbsp;*</span>", OL, 'span')
			}else if (sp)
			  RMNod(sp)
		}
	}
}

FoClass.prototype.Verif = function(D) {
	var Nom, Msg='', Cto;
	for (Nom in this.all) {
		Cto = this.all[Nom];  if (D && !Contains(D,Cto.Ctrl))  continue;
		Msg += Cto.Verif()
	}
	return Msg
}

FoClass.prototype.Url = function() {
	var O, Cto, Ctl, re='', V, Nom
	for (Nom in this.all) {
		Cto  = this.all[Nom];  Ctl = Cto.Ctrl;  if (LX(Ctl,'noUrl'))  continue;
		V = Cto.Val()
		if (V) {
			re+='&'+Nom+'='+encodeURIComponent(V)
		}
	}
	return re
}

FoClass.prototype.Rech = function()   {
	var Li, a, O
	Li = this.Url();  if (!Li)  return
	O = this.all['_action'];  a = O.Val();		//alert(a+crr+Li)
	ExecAction(a, Li)
}

FoClass.prototype.Affs  = function(List,Tag) { var T, Cto;  T = List.split(',');  for (i in T) { if ((Cto=this.all[T[i]]))  Cto.Aff(Tag) } }
FoClass.prototype.Hides = function(List,Tag) { var T, Cto;  T = List.split(',');  for (i in T) { if ((Cto=this.all[T[i]]))  Cto.Hide(Tag) } }
FoClass.prototype.Disabl = function(List,V)  {
	var T, D, Cto;
	D = $E(List,this.Div)
	if (D) {
		$(':input',D).each(function() { this.disabled = V })
	}else{
		T = List.split(',');  for (i in T) { if ((Cto=this.all[T[i]]))  Cto.Ctrl.disabled = V }
	}
}

FoClass.prototype.PreparSov = function() {
	Edit_to_Memo()
}
FoClass.prototype.Sov = function(Opt)   { if (this.Table)  return this.Table.Sov(Opt) }
FoClass.prototype.Suppr = function(Btn) {
	var O = ElemPClass(Btn,'Fo');  if (O && O.Fo.Grid)  O.Fo.Suppr();  else if (this.Table)  this.Table.Suppr()
}

FoClass.prototype.Change = function(Cto) {
	var Ctl, S, V, O
	Ctl = Cto.Ctrl
	if ((S=Ctl.className)) {  // Appel d'un ChangeClass ?
		var T = S.split(' ')
		for (O in T) { V = T[O] }
	}
	if (this.Vue)  this.Vue.ChangeCtl(Cto)
}

FoClass.prototype.toJS = function() {  return this.Table.toJS() }

FoClass.prototype.toString = function() {
	var C, Nom, H=this.Nom+cr+'-----'+cr
	for (Nom in this.all) {
		C = this.all[Nom]
		H+= Nom+', '+C.V+cr
	}
	return H+cr
}


// ====================================      CTL       ===============================
var CtlClass = function (Fo, Nom, Ch, TypAff) {
	var id, Ctl, T, Lib, O
	if (typeof(Ch)=='string')  Ctl = LID(Ch);  else  Ctl = Ch
	if (!(id=LX(Ctl,'name')))  id = Ctl.id
	if (!Fo.all[id]) {
		Fo.all[id] = this
		if (!TypAff)  TypAff = LX(Ctl,'TypAff')

		var NomR = Nom;  if (Right(Nom,2)=='[]')  NomR = Isole(Nom,'[',1)
		if (!(Lib=LX(Ctl,"Lib")))  Lib = LX(Ctl,"title");
		if (!Lib) { O = Elem(Ctl, "O.tagName=='LABEL'", true);	 if (O)  Lib = LText(O); }
		if (!Lib)  Lib = NomR
		this.divAide = $('.aideCh',Ctl.parentNode).get(0)

		this.id			= id
		this.Fo			= Fo
		this.all    = {}  // liste des ctrl (radio=plusieurs)
		this.Nom		= Nom
		this.NomR		= NomR
		this.Lib		= Lib
		this.TypAff	= TypAff
		this.Typ2		= LX(Ctl,'Typ2')
		this.bd			= ze(LX(Ctl,'bd'))
		this.Ctrl		= Ctl
		this.MsgIn	= null
		this.V			= null
		this.Champ	= null
		this.NonVide = this.NonZero = this.Verif_IP = this.Verif_eMail = 0

		if ((T=this.Fo.Table)) {
			if ((Ch=T.all[Nom])) {
				this.Champ = Ch;  Ch.Cto = this;  Ch.Ctrl = this.Ctrl
			}
		}
		this.ValDef()
	}else{
	  this.id = '';   // pour éviter les doublons, par exemple sur les RADIO
	}
	this.Init()
}

CtlClass.prototype.Init = function(Ctl) {
	var d1, d2, S, O, Tag, T, j, Fo = this.Fo
	Ctl = Ctl || this.Ctrl
	Ctl.Cto = this;  if (!(S=(Ctl.id || Ctl.name)))  return
	Tag = Ctl.tagName
	S = Ctl.id || this.Nom
	if (!this.Label) {
		if (!(O=$('label[forhl|=lb'+S+']').get(0)))  if (!(O=$('label[for|='+S+']').get(0)))  O = LTags(Ctl.parentNode,'LABEL',0);		//if (O1) alert(Lout(O1)+crr+Lout(Ctl))
		this.Label = O
  }
	if (Tag=='SELECT') {
		if ((S=LX(Ctl,'Ajout')))  this.setCB(S)
		if ((S=LX(Ctl,'setCB'))) {
			this.setCB(JST(S))
		}
		if ((S=LX(Ctl,'chSuit')) && (O=Fo.getCtl(S)))  Hide(O,'DIV')
	}else if (Ctl.type=='radio' && (!Ctl.value || Ctl.value=='on')) {
		if ((O=$('label[for|='+Ctl.id+']').get(0)))  Ctl.value = LText(O)
	}
	if (!LVal(Ctl) && (S=LX(Ctl,'Msg'))) { Ctl.value=S;  Ctl.Cto.MsgIn = S }
	if ((S=LX(Ctl,'Verif'))) {
		T = S.split(',');
		for (j in T) {
			switch(T[j]) {
			  case 'NonVide': this.NonVide = 1;  break
			  case 'NonZero': this.NonZero = 1;  break
			  case 'IP':  this.Verif_IP = 1;  if (this.TypAff=='D')  this.Verif_Date = 1;  break
			  case 'eMail':  this.Verif_eMail = 1;  break
			}
		}
	}
	if (Ctl.type=='checkbox' || Ctl.type=='radio') { if (!Ctl.onclick)  Ctl.onclick = onChange; }else if (!Ctl.onchange)  Ctl.onchange = onChange
	if (!Ctl.onfocus)  Ctl.onfocus = onFocus
	if (!Ctl.onblur)  Ctl.onblur = onBlur
}

CtlClass.prototype.Destroy = function() {
	var Ctl, S
	Ctl = this.Ctrl;  Ctl.onclick = Ctl.onchange = Ctl.onfocus = Ctl.onblur = null
	this.Champ.Ctrl = null
	RMNod(Ctl)
}

CtlClass.prototype.ValDef = function(Opt) {
	var V, S, Ctl, Ch
	Ctl = this.Ctrl;		//alert(Lout(Ctl))
	if (!Opt)  Opt = {}
	if (!Opt.sansMeta && (S=LX(Ctl,'meta'))) {
		//if ((Ch=this.Fo.Ctrls[S]))  PVal(Ctl, Meta(Ch, this.Nom))
		if ((Ch=this.Fo.all[S]))  PVal(Ctl, Meta(Ch.Ctrl, this.Nom))
		//wh("ValDef: "+this.Nom+', meta='+S)
	}
	V = LVal(Ctl)
	Ch = this.Champ
if (Ch.Nom=='BanqDon') {
//aa =1
}
	if (!V) {
		if ((S=LX(Ctl,'Valeur'))) {   // Contrairement à ValDef, Valeur ne dépend pas de ValCle
			if (S.substr(0,1)=='=')  V = Eval(S.substr(1));  else  V = S
			if (!Ch || (Ch && !Ch.Table.ValCle))  PX(Ctl,'adUrl',1)
		}
		if (!Ch || (Ch && !Ch.Table.ValCle)) {
			if ((S=LX(Ctl,'ValDef'))) {
				if (S.substr(0,1)=='=')  V = Eval(S.substr(1));  else  V = S
//alert(Ch.Nom+crr+V+crr+S)
			}
		  //if (this.Fo.Typfo=='Rech')  PX(Ctl,'adUrl',2)  //!!!!! Suppr tempo parce que quand ValCle est défini après, tout est avec adUrl et donc Table.Url prend tout
		}
		if (Ch && (S=Ch.V))  V = S
		//if (Ch)  alert(Ch.Nom+cr+Ch.V)
	}else{
		if (this.Fo.TableAutoCre) { Ch.Val(V);  Ch.oldV=V }
	}
	if (Ch && !Ch.Table.ValCle && !Ch.V)  { Ch.Val(V);  Ch.oldV=V }  // placé pour Roche / Html.htm / contact_activ /
	PVal(Ctl,V);
}

CtlClass.prototype.Format = function() {
	var O, V, C, Ch, Typ, TypAff, Opt={}
	O = this.Ctrl
	TypAff = this.TypAff
	if ((Ch=this.Champ)) { Typ = Ch.Typ; }
	V = Trim(LVal(O))
	V = FormatChamp(V, Typ, TypAff, Opt)
	return V
}

CtlClass.prototype.Verif = function() {
	var V, S, Msg='', Termin='', Err, d1, d2

	var Ctl = this.Ctrl;
	V = LVal(Ctl)
	d1 = ElemPClass(Ctl,'allNonVide')
	d2 = (ElemPClass(Ctl,'oubliHide') && !Ctl.offsetHeight);  if (d1 && d2)  d1 = 0
	if (!d2 && (this.NonVide || d1) && !this.NonZero) {
		Err = false
		switch (Ctl.type) {
			case 'radio':  if (!LitRadio(Ctl))  Err=true;  break
			case 'checkbox':  if (!d1 && !Ctl.checked)  Err=true;  break
			default:  if (!Ctl.value || ((S=LX(Ctl,'Msg')) && V==S))  Err=true
		}
		if (Err) {
			if (Ctl.type=='checkbox') { Msg = "La case à cocher ";  Termin="e" }
			Msg+= "[" + this.Lib + "] doit être renseigné"
			Msg+= Termin + '\n'
		}
	}
	//alert(this.Nom+crr+d1+','+d2+crr+this.NonVide+','+this.NonZero+crr+Msg)
	if (this.NonZero && !d2)  if (!V || !zed(V))  Msg+= "'" + this.Lib + "' doit être renseigné\n"
	if (this.Verif_IP)  if ((S=Verif_IP(V)))  Msg+= S+'\n'
	if (this.Verif_Date || (V && this.TypAff=='D'))  if ((S=Verif_Date(V)))  Msg+= S+'\n'
	if (this.Verif_eMail)  if ((S=Verif_eMail(V)))  Msg+= S+'\n'
	return Msg
}

CtlClass.prototype.Traite = function() {  // Traite un champ, en principe après la maj d'un autre champ Source
	var Ctl, Sql, S, J
	Ctl = this.Ctrl
	if ((Sql=FormeSql(LX(Ctl,'Sql')))) {
		Sql = Replace(Sql,'chSo',Ctl.chSo.Val())
		this.setCB({Pgm:"LitSql",Sql:Sql},{Clear:1})
	}
}

CtlClass.prototype.Change = function() {
	var Cto, Ctl, S, V, O;      //alert(Lout(this.Ctrl))
	V = this.Format()
	this.Val(V)
	Ctl = this.Ctrl
	if ((O=this.Fo.getCtl(LX(Ctl,'chSuit')))) {
		Aff(O,'DIV')
		if (O.Cto) {
			O.chSo = this
			O.Cto.Traite()
		}
	}
	this.Meta()
	if ((S=LX(Ctl,'Source'))) {
		var B, CtS = this.Fo.all[S]
		B = ze(LX(Ctl,'Bit'))
		if (B) {
			if (Ctl.checked)  CtS.Val(CtS.Val() | B);  else  CtS.Val(CtS.Val() ^ B)
		}
	}
	this.finInit()
	this.Fo.Change(this)
	//if (this.Grid)  alert(Lout(Cto.Ctrl))
	if (this.finChange)  this.finChange(V)
	PX(this.Ctrl,'Interactif','change')
}

CtlClass.prototype.Meta = function() {
	var Cto, Ctl, M, S, V;			//alert(this.Nom)
	Ctl = this.Ctrl
	if ((S=LX(Ctl,'meta'))) {
		if ((Cto=this.Fo.all[S]))  M = Cto.Ctrl;  else  M = this.Fo.Ctrls[S]
		if (M) {
			Meta(M, this.Nom, LVal(Ctl));  if (Cto)  Cto.Val(LVal(M))
		}
	}
}

CtlClass.prototype.setCB = function(Liste, Opt) {
	// setCB='{Pgm:"LitSql",NomT:"prodrub"}'   ou   =App.CB.Banque  ou  {Pgm:"LitSql",NomT:"base",Sql:"SELECT Ref, Titre FROM l_base WHERE clp=116"}
	// setCB=',(?);08,08;09,09'
	// setCB=SelDat
	var Li, Sql, Param, S, V
	if (this.Champ)  V = this.Champ.V
	if ((S=this.Ctrl.AjDebMemo))  Opt.AjDeb = S
	if (isObj(Liste) && Liste.Pgm) {
		Li = '&Pgm='+Liste.Pgm;  if ((S=Liste.NomT))  Li+='&NomT='+S;  if ((S=Liste.NomC))  Li+='&NomC='+S;  if ((S=Liste.Sql))  Li+='&Sql='+encodeURIComponent(S);   //alert(Li)
		Param = { Cto:this, ValDef:V, Opt:Opt }
		PHB(decodeURIComponent(Li+AjUrl),'Action','Act');
		XmlPost(Li+AjUrl, '', this.Callback_setCB, Param)
	}else{
		//if (Liste.substr(0,1)=='=')  alert(this.Nom+crr+Liste)
		Opt=Opt||{};  if (this.Champ && V)  Opt.ValDef = V
		if (Liste.substr(0,8)=='=App.CB.') {
				CBData(this.Ctrl, Liste.substr(8), Opt);  return
		}else if (Liste.substr(0,1)=='=')
			Liste = eval(Liste.substr(1))
		setComboBox(this.Ctrl, Liste, Opt)
	}
}

CtlClass.prototype.Callback_setCB = function(re,Param,reJ) {
	var J, Cto = Param.Cto
	PHB(reJ,'setCB','Act');
	var J = Param.Opt || {};  if (!J.ValDef)  J.ValDef = Cto.Champ.V
	setComboBox(Param.Cto.Ctrl, reJ, J)
}

CtlClass.prototype.finInit = function() {
	var O, Ctl = this.Ctrl
	if (App.tinyMCE && hasClass(Ctl,'mceEditor')) {
		if ((O=tinyMCE.getInstanceById(Ctl.id || this.Nom))) { O.load(); }
	}
}

CtlClass.prototype.ChoixFic = function(Dest) {
	var H
	if (!Dest)  Dest='doc';  //if (Dest.substr(0,7)=='biblio/')  Dest = Dest.substr(7)
	H = "/kiwi/explor/ExplorVue.php?Doss=" + Dest + '&Fo=' + this.Fo.Nom + '&Ctl=' + this.Nom + AjUrl
	window.open(H, "", "toolbar=no,menubar=no,scrollbars=yes,resizable=yes,status=yes,width=600,height=550")
}

CtlClass.prototype.Focus = function() { try { this.Ctrl.focus() }catch(e){} }

CtlClass.prototype.noteFocus = function() {
	PX(this.Ctrl,'Interactif','focus');
	var d1, d2;  if ((d1=this.divAide) && (d2=this.Fo.divAide)) { setTimeout(function() { d2.innerHTML = d1.innerHTML;  Aff(d2); },700); }
	this.onFocus();
}
CtlClass.prototype.onFocus = function() {}

CtlClass.prototype.noteBlur = function() {
	var Ch, V, O = this.Ctrl;    //alert(Lout(O))
	var d1, d2;  if ((d1=this.divAide) && (d2=this.Fo.divAide)) { setTimeout(function() { d2.innerHTML = '';  Hide(d2) },500); }
	if (O.type=='text' && LX(O,'Interactif')=='focus') {
		PX(O,'Interactif','blur');
		//Ch = this.Champ   // pour régler le cas du choix d'une valeur déjà saisie dans un champ texte (onchange n'est pas appelé)
		//if (Ch) {
		//	if (Ch.siMaj())  this.Change();  else if ((V=LVal(O)) && Ch.V!=V)  this.Change();
		//}else
		//	this.Change();
		//this.onBlur();
	}
}
CtlClass.prototype.onBlur = function() {}

CtlClass.prototype.Val = function(V) {
	var Ch, Ctl
	Ctl = this.Ctrl
	if (V===undefined) { V = LVal(Ctl);  if (this.MsgIn && V==this.MsgIn)  V='';  return V }
	if (this.MsgIn && V==this.MsgIn)  V = ''
	if ((Ch=this.Champ)) {
		Ch.Val(V)
	}else
		PVal(Ctl,V)
}

CtlClass.prototype.ValSql = function() { var Ch;  if ((Ch=this.Champ))  return Ch.ValSql();  else  return this.Val() }

CtlClass.prototype.Aff  = function(Tag) { if(Tag==undefined)  Tag='DIV';  Aff(this.Ctrl,Tag) }
CtlClass.prototype.Hide = function(Tag) { if(Tag==undefined)  Tag='DIV';  Hide(this.Ctrl,Tag) }



// ====================================      TABLE       ===============================
var TableClass = function(Nom, Proto) {
	var J
	this.Nom		= Nom
	this.NomT		= Nom
	this.NomC
	this.ChCle	= null
	this.ValCle
	this.TypCle
	this.Fo			= null
	this.BD
	this.all		= []
	this.nbMaj	= 0
	this.ChampClass = ChampClass
	if (Proto)  for (var K in Proto)  this[K] = Proto[K]
	J = this.BD;  if (J) { if (J.NomT)  this.NomT = J.NomT;  if (J.NomC)  this.NomC = J.NomC; }
	if (Tables[Nom])  delete(Tables[Nom]);  Tables[Nom] = this
	return this
}

TableClass.prototype.Add = function(Nom, Typ, Taille, V, JS) {
	var Ch
	if (!JS && (JS=this.Champs))  JS=JS[Nom]
	if ((Ch=this.all[Nom])) {
		if (Typ!=undefined)  Ch.InitCh(this, Nom, Typ, Taille, V, JS)
	}else{
		this.all[Nom] = new this.ChampClass(this, Nom, Typ, Taille, V, JS)
		if (Nom==this.NomC)  this.ChCle = this.all[Nom]
	}
	return this.all[Nom]
}

TableClass.prototype.InitVals = function() { for (var Nom in this.all)  this.all[Nom].V = this.all[Nom].oldV }

TableClass.prototype.ReInit = function(siVal) {
	var Ch, Nom
	this.ValCle = null
	for (Nom in this.all) {
		Ch = this.all[Nom];
		if (Ch.Cto.Typ2=='meta')  Ch.ReInit(siVal)
		//if (Ch.Cto.Typ2=='meta')  alert(Lout(Ch.Cto.Ctrl))
	}
	for (Nom in this.all) {
		Ch = this.all[Nom];  if (Ch.Cto.Typ2!='meta')  Ch.ReInit(siVal)
	}
	this.finReInit(siVal)
}
TableClass.prototype.finReInit = function(siVal) {}

TableClass.prototype.ImportDataJS = function(TJS) {   // Import d'1 tableau de champ
	var Nom, V, R
	if (!TJS)  return
	for (Nom in TJS) {
		R = TJS[Nom];  V = R.V;     //alert(JSONS(R))
		switch (R.Typ) {
		  case 'N':  if (V==0)  V='';  break;
		  case 'D':  V = ConvDate(V);  break;
		}
		this.Add(Nom, R.Typ, R.Siz, V)
	}
	this.ChCle = this.all[this.NomC]
	this.initie = 1
}

TableClass.prototype.ImportRecord = function(R, Opt) {  // Import d'1 recordset R
	if (!R)  return
	var Nom, V, Ch, Cto, Ctl, S
	if (typeof(R)=='string')  R = JSOND(R);
	if (TypOf(R)=='Array')  R = R[0];
	if (!Opt)  Opt = {}
	this.R = R
	this.debImport()
	for (Nom in R) {
		V = R[Nom]
		Ch = this.all[Nom]
		if (!Ch)  if (Opt.noAddCh)  continue;  else  Ch = this.Add(Nom)
		if ((Cto=Ch.Cto)) {
			Ctl = Cto.Ctrl
			switch (Cto.TypAff) {
				case 'N':  if (V==0)  V='';  break;
				case 'D':  V = ConvDate(V);  break;
				default:
					switch (Ctl.type) {
						case "checkbox":  if (isStr(V))  V = eval(V.toLowerCase());  break;
					}
			}
			if ((S=LX(Ctl,'CtlFils'))) {  // Champs dont la valeur doit modifier d'autres
				var Cto2, B, D = $E(S,this.Fo.Div)
				$(':input',D).each(function() {
					if (LX(this,'Source')==Nom) {
						if ((B=ze(LX(this,'bit')))) {
            	this.checked = V & B;		//alert(Lout(this)+crr+V+crr+B+crr+(V & B))
						}
					}
				})
			}
		}
		if (isObj(V))  V = JSONS(V)
		Ch.Val(V)
		Ch.oldV	= Ch.V
		if (Cto)  Cto.finInit()
	}
	if (this.NomC && (Ch=this.all[this.NomC]))		this.ValCle = Ch.Val()
	this.Fo.ValDef()
	this.Fo.onReInit()
	this.finImportRecord(R, Opt)
}
TableClass.prototype.debImport = function(R) {}
TableClass.prototype.finImportRecord = function(R, Opt) {}

TableClass.prototype.ExportRecord = function() {  // Export d'1 recordset R
	var Nom, R={}, V, Ch
	for (Nom in this.all) {
		Ch = this.all[Nom]
		R[Nom] = Ch.Val()
	}
  return R
}

TableClass.prototype.Url = function(Opt, D) {
	// champs maj de la table + ctrl avec req ou adUrl ou commence par _. req = toujours, adUrl = seulement si champs importants modifiés
	var O, Cto, Ctl, Ch, S, JS={}, JC={}, V, Nom, NomR
	var ValCle = this.ValCle
	if (!Opt)  Opt= {};  if (typeof(Opt)!='object')  Opt = {Toujours:Opt}
	var noMaj = Opt.Toujours
	if (noMaj==-1) {
		if (this.NomC)  JS[this.NomC] = ValCle
	}else{
		// Cto ayant changés
		for (Nom in this.all) {
			Ch = this.all[Nom];  V = Ch.V
			Ctl = Ch.Ctrl;  if (LX(Ctl,'meta') || (D && !Contains(D,Ctl)))  continue;
			if (noMaj==4 || ((noMaj==2 && V) || (noMaj!=2 && (V!=Ch.oldV || (noMaj!=3 && !ValCle && V) || (noMaj==1 && V))))) {  // nomaj 2=rech, 3=test maj
				V = Ch.ValSql();  //V = Replace(V,'&','%26amp;');
				//if (ie && navV<8) { V = Replace(V,'\r','\\r');  V = Replace(V,'\n','\\n'); }
				//if (isStr(V))  V = Replace(V,'"','\\"');
				//V = encodeURIComponent(V)
				JS[Ch.Cto.NomR] = V
			}
		}
	}
	// autres champs
	if (this.Fo && noMaj!=3) {  // && !Opt.noAutresCh
		if (this.ChCle && this.Fo.TypFo!='Rech') {
			S = this.ChCle.Nom;  if (!JS[S])  JC[S] = this.ChCle.ValSql()
		}else{
			//alert('Aucune clé dans le formulaire');  return   : annulé pour form de recherche
		}
		for (Nom in this.Fo.all) {
			Cto = this.Fo.all[Nom];  Ctl = Cto.Ctrl;  NomR = Cto.NomR
			if (LX(Ctl,'noUrl') || LX(Ctl,'meta') || JS[NomR] || (D && !Contains(D,Ctl)))  continue;		//alert(Nom+crr+Lout(Ctl))
			V = Cto.ValSql()
			if (LX(Ctl,'req')) {
				JS[NomR] = V
			}else{
				S = ze(LX(Ctl,'adUrl'))
				if ((Nom.substr(0,1)=='_' || S==1 || (S==2 && V))) { JC[NomR] = V }
			}
		}
		if (!ObjAsChild(JS) && !noMaj) JC={}
	}
	copyObj(JS,JC)
	return JS
}

TableClass.prototype.Sov = function(Opt) {
	// fo_CalV1.Sov({Pgm:'LoadPHP:'+PathR})
	var Fo, Vu, Cs, S, Param, JS, JD, BD, DataIn
	if (!this.debSov())  return
	Opt = Opt || {}
	Fo = this.Fo
	Cs = Fo.Ctrls;  if ((S=Fo.Verif())) { alert(S);  return }
	Fo.PreparSov()
	JD = this.Url(Opt.Toujours);  if (!Opt.execAjax && !ObjAsChild(JD)) { this.SovBack0('', {'parent':this, Opt:Opt});  return 1 }  // execAjax permet de tjrs exécuter ExecAction même s'il n'y a rien à sov, mais il peut y avoir un traitement php qui suit l'action de sov
	//alert(this.Nom+crr+JSW(JD));  return
	if (JD.Action)
		JS = JD
	else if (JD._Action) {
		JS = {};  DataIn = {}
		for (S in JD) {
			if (S.substr(0,1)=='_')  JS[S.substr(1)] = JD[S];  else  DataIn[S] = JD[S];
		}
		JS.DataIn = DataIn
	}else{
		if (!(BD=this.BD))  if ((Vu=this.Fo.Vue))  BD = Vu.BD;  else  BD = {NomT:this.NomT, NomC:this.NomC}
		if (!BD)  BD = {}
		BD.ValCle = this.ValCle;  BD.DataIn = JD
		JS = {Action:"Sov", BD:BD };      //alert(JSW(JS));  //return
	}
	ExecAction(JS, {parent:this, Opt:Opt, Callback:this.SovBack0})
	return 1
}

TableClass.prototype.debSov = function() { return 1 }

TableClass.prototype.SovBack0 = function(re, Param, reJ) {
	var This, Fo, CallB, J, T, NomC, S
	if (Param) { This = Param.parent;  CallB = Param.Opt && Param.Opt.Callback; }    // Pour un sov de base, Fo.Table.backVal.cl1 contient la clé (Fo = This)
	if (!This)  This = this
	Fo = This.Fo;  NomC = This.NomC
	if (reJ && reJ.ValCle && NomC && NomC!='Cle')  This.all[NomC].Val(reJ.ValCle)   // !=Cle => pas pour cms, sinon cl1 entre dans Cle à la 2° sov
	This.InitVals()
	if (Fo.ssFos) {
		for (J in Fo.ssFos) {
			T = Fo.ssFos[J];  S = T.Sov();  if (!S)  return
		}
	}else if (Fo.foParent)
		return
	if (!CallB)  CallB = This.SovBack
	if (re) {
		PHB(reJ,'SOV','Fo');  PHB(re,'SOV','Fo',1);
		if ((T=DecoupeJS(re))) { J = T.JS || T;  This.backVal = J.backVal || J; }
	}else{
		This.backVal = { retour:'sov0' }  // pas de retour : pas champs à sauvegarder ?
	}
	CallB(re, Param, This.backVal)
}

TableClass.prototype.SovBack = function(re, Param, reJ) {   // reJ : {retour:true, ValCle:15, TypMajOk:Ajout, Msg:}
	if (re==undefined)  return;		//alert(re)
	if (this.backVal && !this.backVal.retour) { alert(this.backVal.Msg);  return }
	TraitResult(re);
}

TableClass.prototype.Suppr = function() {
	if (!this.ValCle) { alert("Rien à supprimer");  return }
	if (!confirm("D'accord pour supprimer cette fiche ?"))  return
	var JD = this.Url(-1);
	var JS = {Action:"Suppr", BD:{NomT:this.NomT, NomC:this.NomC, ValCle:this.ValCle, Relation:this.Relation, DataIn:JD} };      //alert(JSW(JS))
	ExecAction(JS, {parent:this, Callback:this.SupprBack0})
}

TableClass.prototype.SupprBack0 = function(re, Param, reJ) {
	if (!reJ || (reJ && !reJ.retour)) { alert("La suppression n'a pas fonctionné");  return }
	PHB(reJ,'SUPPR','Fo');  PHB(re,'SUPPR','Fo',1);
	Param.parent.SupprBack(re, Param, reJ)
}

TableClass.prototype.SupprBack = function(re, Param, reJ) {
	if (re==undefined)  return;
	//var T = Decoupe(re);  if (T && T.JS && T.JS.backVal && !T.JS.backVal.retour) { alert(T.JS.backVal.Msg);  return }
}

TableClass.prototype.toJS = function() {
	var Cto, Ctl, Ch, JS, Nom, V
	JS = { NomT:this.Nom, NomC:this.NomC, ValCle:this.ValCle, R:{} }
	for (Nom in this.all) {
		Ch = this.all[Nom];  V = Ch.V
		Ctl = Ch.Ctrl;  if (LX(Ctl,'meta'))  continue
		JS.R[Nom] = Ch.Val()
	}
	return JS
}

TableClass.prototype.toString = function() {
	var Ch, H='', Nom
	H+='Nom='+this.Nom+', NomT='+this.NomT+', NomC='+this.NomC+', ValCle='+this.ValCle+crr
	for (Nom in this.all) {
		Ch = this.all[Nom]
		H+= Nom+', '+Ch.Typ
		if (Ch.Siz)  H+= ', '+Ch.Siz+cr
		H+= ', '+Ch.oldV+' = '+Ch.V+cr
	}
	return H+cr
}

// ====================================      CHAMP       ===============================
var ChampClass = function(Table, Nom, Typ, Siz, Valeur, Proto) {
	var Fo, Cto
	this.InitCh(Table, Nom, Typ, Siz, Valeur, Proto)
	this.Cto	= null
	this.Ctrl	= null
	this.Maj	= 0

	if ((Fo=this.Table.Fo)) {
		if ((Cto = Fo.all[Nom])) {
			Cto.Champ = this;  this.Cto = Cto;  this.Ctrl = Cto.Ctrl
		}
	}
}

ChampClass.prototype.InitCh = function(Table, Nom, Typ, Siz, Valeur, Proto) {
	this.Table  = Table
	this.Nom	= Nom
	this.Typ	= Typ || 'T';
	this.Siz	= Siz;
	this.V		= this.InitV(Valeur)
	this.oldV	= this.V
	if (Proto)  for (var K in Proto)  this[K] = Proto[K]
}

ChampClass.prototype.InitV = function(Valeur) {
	var V
	if (Valeur==undefined)
		V = null
	else
		switch(this.Typ) {
			case 'T': V = Valeur;  break
			case 'M': if (!(V=Valeur) && this.Table)  V = LVal(this.Table.Nom+"_"+this.Nom);  break
			case 'B': if (typeof(Valeur)=="string")  V = eval(Valeur.toLowerCase());  else  V = Valeur;  break
			default:	V = Valeur
		}
	return V
}

ChampClass.prototype.ReInit = function(siVal) {
	if (this.Nom.substr(0,1)=='_')  return
	var V, O, Cto = this.Cto
	if (isObj(siVal)) { V = siVal[this.Nom];  if (V==undefined) V=''; }else  V = (siVal) ? this.V : ''
	this.Val(V);  Cto.Val(V);  this.oldV	= this.V
	//Cto.ValDef({sansMeta:0})   // sansMeta : dans le cas où le memo meta n'est pas encore Reinit, un champ réinitialisé reprendra la valeur du meta
	if (siVal!==0)  Cto.ValDef()
	//if (this.Nom=='Descript') { a=11	}
	Cto.finInit()
}

ChampClass.prototype.Val = function(V) {    // Appelé par Table.Add => new ChampClass => ValDef
	var V, Ctl = this.Ctrl, T = this.Table,  Cto = this.Cto
	if (V===undefined) {
		if (Ctl) { V = LVal(Ctl);  if (Cto.MsgIn && V==Cto.MsgIn)  V='' }  else  V = this.V
		return V
	}
	if (Cto && Cto.MsgIn && V==Cto.MsgIn)  V = null
	this.V = V
	if (Ctl)  PVal(Ctl, V, 1)
	if ((Ctl=T.all['ch_'+this.Nom]))  PVal(Ctl.Ctrl,V,1)
	if (Cto)  Cto.Meta()
	if (this.Nom==T.NomC)  T.ValCle = V
	this.finVal(V)
	if (this.Table.Fo.Vue)  this.Table.Fo.Vue.finVal(this)
}
ChampClass.prototype.finVal = function() {}

ChampClass.prototype.ValSql = function() {
	var Cto, C, V
	V = this.Val()
	if ((Cto=this.Cto)) {
		switch(Cto.TypAff) {
			case 'tel': V = ClearText(V, "!isNaN(C) && C!='.' && C!=' '");  break
		}
		C = Cto.Ctrl;  if (C && C.type=='checkbox')  V = C.checked ? 1:0
	}
	return V
}

ChampClass.prototype.Url = function() {  return encodeURIComponent(this.Val()) }

ChampClass.prototype.siMaj = function() { var O, V;  V = this.V || '';  O = this.oldV || '';  return (V!=O) }



// ====================================      ss-PGM       ===============================
var GridClass = function(Fo, Proto) {
	var K, D, Me
	Me = this
	this.Nom	= Fo.Nom
	this.Div	= D = Fo.Div
	this.Fo		= Fo
	this.DivT
	this.Cols
	this.TH
	this.Data = null;  this.nbL  = 0
	$('xmp.infoGrid',D).each(function() {
		if (this.parentNode==D && (S=LX(this,'Typ')))
			Me[S] = JSOND(LText(this));
		else{
			var JS = JSOND(LText(this));  for (S in JS)  Me[S] = JS[S]
		}
	})
	if (Proto)  for (K in Proto)  this[K] = Proto[K]
	this.Cols[this.Fo.NomC] = { Class:"hide", W:"20px", H:"<INPUT name="+this.Fo.NomC+" adUrl=1>" }   // Ajout de la clé
	if (Fo.Droit>4 && !this.Cols.btnSel)  this.Cols.btnSel = { W:"20px", H:"<INPUT name=btnSel class=btnSel type=checkbox>" }
	Fo.Change = this.Change
	Fo.Sov = this.Sov
	Fo.Suppr = this.Suppr
}

GridClass.prototype.AffGrid = function() {
	var TR, K, D = this.Div,  Fo = this.Fo,  J = this.Data,  nb=0
	Fo.Destroy(D,1);  D.innerHTML = '';  this.nbL = 0

	this.DivT = MakeDom('div',D, {Class:'gridT'})
	this.AffTH()
	for (K in J) { this.AffLig(J[K]);  nb++ }
	if (Fo.Droit>4) {
		TR = this.AffLig();
		if (!nb)  AddClass(TR,'gridData')   // Obliger la saisie de la 1° ligne vide si elle contient des NonVide
		TR = MakeDom('div',D, {Class:'gridTR gridBas'})
		$(TR).append("<button title='supprimer les fiches cochées'>Supprimer</button>")
		//$(TR).append("<button onclick='Fos.all.ListPrd.Sov()'>OK</button>")
	}
	Fo.InitFo(D)
	this.onAff()
	//alert(Fo+crr+Fo.Table)
}
GridClass.prototype.onAff = function() {}

GridClass.prototype.AffTH = function() {
	var J, Nom, K, Cols = this.Cols,  Div = this.DivT, TR, TD
	TR = MakeDom('div',Div, {Class:'gridTR'})
	if (this.TH) {
		TR.innerHTML = this.TH
	}else{
		for (Nom in Cols) {
			J = Cols[Nom]
			TD = MakeDom('div',TR, {Class:'gridTH gridTD'})
			TD.innerHTML = (J.Lib) ? J.Lib : '&nbsp;'
			if (J.W)  TD.style.width = J.W
		}
	}
}

GridClass.prototype.AffLig = function(R) {
	var J, Nom, K, TR, TD,  Cols = this.Cols,  Div = this.DivT,  Me = this,  nbL = Me.nbL
	TR = MakeDom('div',Div, {Class:'gridTR', nbL:nbL})
	if (R) { AddClass(TR,'gridData');  AddClass(TR,'gridVerif') }
	for (Nom in Cols) {
		J = Cols[Nom]
		TD = MakeDom('div',TR, {Class:'gridTD'})
		if (J.H)  TD.innerHTML = J.H
		if (J.Class)  AddClass(TD,J.Class)
		$(':input',TD).each(function() {
			var Name = (this.name || Nom)
			this.name = Name+'_'+nbL;		//alert(Lout(this))
			if (J.Lib && !LX(this,'Lib'))  PX(this,'Lib',J.Lib)
			if (R)  PX(this,'ValDef',R[Name])
		})
		if (J.W)  TD.style.width = J.W
	}
	this.nbL++
	this.finAffLig(TR)
	return TR
}
GridClass.prototype.finAffLig = function(TR) {}

GridClass.prototype.LoadData = function() {
	var Sql, Cle, S, Me = this,  Fo = this.Fo
	this.Data = null;
	if (!(Cle=Fo.foParent.Table.ValCle)) { this.AffGrid();  return }
	Sql = "SELECT * FROM "+Fo.NomT+" WHERE "+Fo.Lien+"="+Cle;		//alert(Sql)
	S = '&Pgm=LitSql&Sql='+encodeURIComponent(Sql)
	XmlPost(S+AjUrl, '', function (re,pm,reJ) {
		Me.Data = reJ;		//alert(JSW(reJ)+crr+re)
		Me.AffGrid()
	})
}

GridClass.prototype.getTR = function(O) {	return ElemPClass(O,'gridTR') }
GridClass.prototype.getNo = function(O) {	var TR = ElemPClass(O,'gridTR');  if (TR)  return LX(TR,'nbl') }
GridClass.prototype.getCto = function(TR,Nom) {
	return this.Fo.all[Nom+'_'+LX(TR,'nbl')]
}

GridClass.prototype.getCle = function(TR) {
	var nbL = '_'+LX(TR,'nbL'),  NomC = this.Fo.NomC+nbL;  return this.Fo.all[NomC].Val()
}

GridClass.prototype.Change = function(Cto) {
	var nbL, S,  TR = ElemPClass(Cto.Ctrl,'gridTR'),  Fo = this,  G = this.Grid
	nbL = LX(TR,'nbL')
	AddClass(TR,'gridMaj');
	if ((S=Fo.Verif(TR))) {
		DelClass(TR,'gridVerif')
	}else{
		AddClass(TR,'gridData');  AddClass(TR,'gridVerif');
		if (nbL==G.nbL-1 && Fo.Droit>4) {
			D = G.AffLig()
			this.InitFo(D)
		}
	}
	G.finChange(Cto)
}
GridClass.prototype.finChange = function(Cto) {}

GridClass.prototype.Sov = function() {
	var Me = this.Grid,  Fo = this,  T = Fo.Table,  Ch, Lien, S, Msg='', ValCle
	if (!(Lien=Fo.foParent.Table.ValCle)) { alert("Sauvegarde impossible sans clé parent");  return }
	ValCle = T.ValCle
	$('.gridMaj',Fo.Div).each(function() {
		if ((S=Fo.Verif(this)))  Msg+=S+cr
	})
	if (Msg) { alert(S);  return }
	$('.gridVerif',Fo.Div).each(function() {
		var JS, JD, DI={}, nbL = '_'+LX(this,'nbL'),  NomC = Fo.NomC+nbL
		if ((Ch=T.all[NomC]))  T.ValCle = Ch.Val()  // Pour que Url ne trouve que les modifications et non l'ensemble des lignes
		JD = T.Url(0,this);
		if (Ch)  T.ValCle = ValCle  // T correspond au Fo principal, donc la clé ne correspond pas
		if (ObjAsChild(JD)) {
			for (k in JD)  DI[k.substr(0,k.length-nbL.length)] = JD[k]
			DI[Fo.Lien] = Lien
			var BD = (Fo.BD) ? Fo.BD : {NomT:Fo.NomT, NomC:Fo.NomC}
			BD.ValCle = T.ValCle;  BD.DataIn = DI
			JS = { Action:"Sov", BD:BD };      //alert(JSW(JS));
			ExecAction(JS, {parent:Me, Callback:function(re, PM, J) {
				if (J.ValCle)  T.all[NomC].Val(J.ValCle);     //alert(JSW(J))
			} })
		}
	})
	return 1
}

GridClass.prototype.Suppr = function() {
	var T=[], L, k, Li='', Msg="D'accord pour supprimer ",  Fo = this,  G = Fo.Grid
	$('.gridData .btnSel',Fo.Div).each(function() {
		if (this.checked)  T.push(ElemPClass(this,'gridData'))
	})
	if (!(L=T.length)) { alert("Aucune ligne n'a été sélectionnée");  return }
	Msg+= (L>1) ? "ces "+L+" éléments ?":"cet élément ?";  if (!confirm(Msg))  return
	for (L in T) {
		if ((k=G.getCle(T[L])))  Li+=' OR '+Fo.NomC+'='+k
		Fo.Destroy(T[L],1)
		RMNod(T[L])
	}
	if (Li) {
		Sql = "DELETE FROM "+Fo.NomT+" WHERE "+Li.substr(4)
		ExecAction({Action:"ExecSql",Sql:Sql}, function(re, PM, J) {
			if (!J.retour)  alert("Aucun élément supprimé");  else  alert(J.retour+" élément(s) supprimé(s)")
		})
	}
}


// ====================================      ss-PGM  FO     ===============================
function onChange(e) {
	var Cto, S
	if ((Cto=EventCto(e)))  Cto.Change()
	if (window.onChange2)  window.onChange2(e)
	//AnnulEvent(e)
	//return false
}

function onFocus(e) { var Cto;  if ((Cto=EventCto(e)))  Cto.noteFocus(); }
function onBlur(e) { var Cto;  if ((Cto=EventCto(e)))  Cto.noteBlur(); }
function EventCto(e) { var O, S;  O = EventCtrl(e);  return O.Cto }


function FormatChamp(V,Typ,TypAff,Opt) {
	var O, V, C, Test, p
	if (!Opt)  Opt = {}
	if (typeof(V)=='string') { C = V.substr(0,1);  if (C=='=')  V = V.substr(1) }
	if (!V)  return C+V
	if (TypAff=='N')  Typ = 'N'
		//alert(Typ+cr+TypAff+cr+V)
	switch (Typ) {
		case 'N':
			V = Replace(V,",",".");  S = parseFloat(V);
			if (S!=V) { if (isNaN(S)) S='';  if (V) Opt.MsgErr = V + " n'est pas un nombre. Conversion automatique en '" + S + "'";  V=S }
			break
	}
	switch (TypAff) {
		case 'D':  V = ConvDate(V);  break
		case 'email':
			Test = new RegExp("^([a-zA-Z0-9_-])+([.]?[a-zA-Z0-9_-]{1,})*@([a-zA-Z0-9-_]{2,}[.])+[a-zA-Z]{2,3}$");
			if (!Test.exec(V))  Opt.Msg = "Adresse invalide (format : nom@domaine.dom)"
		  break
		case 'minus':  if (C!="=")  V = V.toLowerCase();  break
		case 'majus':  if (C!="=")  V = V.toUpperCase();  break
		case 'minus2':  V = Minus(V);  break
		case 'majus2':  V = Majus(V);  break
		case 'NP':  	 if (C!='=')  V = NomPropre(V);  		break
		case 'tel':
			V = ClearText(V, "!isNaN(C) && C!='.' && C!=' '")
			O = V.match(/([0-9]{1,2})/g);  V = O.join(' ')
			if (V.substr(0,2)=='00')  V = '00'+V.substr(3)
			break
	}
	return V
}

function Verif_IP(V) {
	var M='', reg = /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/ ;
		//\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b
	if (V.match(reg))  M = "L'adresse ip " + V + " n'est pas valide";  return M
}
function Verif_Date(V) {    //alert(Verif_Date("12/01/2003 10:08"))
	var M='', reg, f1, f2, f3
	f1 = "[0-9]{2}[/]{1}[0-9]{2}[/]{1}[0-9]{4}";  f2 = "[ ][0-9]{2}[:]{1}[0-9]{2}";  f3 = "[ ][0-9]{2}[:]{1}[0-9]{2}[:]{1}[0-9]{2}"
	reg = new RegExp("^"+f1+"$","g");
	if (!reg.test(V)) {
		reg = new RegExp("^"+f1+f2+"$","g");
		if (!reg.test(V)) { reg = new RegExp("^"+f1+f3+"$","g");  if (!reg.test(V))  M = V + " n'est pas au format date (ex : 08/02/2002)" }
	}
	return M
}
function Verif_eMail(V) { if (!V)  return;  var M='', reg = new RegExp("^([a-zA-Z0-9_-])+([.]?[a-zA-Z0-9_-]{1,})*@([a-zA-Z0-9-_]{2,}[.])+[a-zA-Z]{2,3}$");  if (!reg.exec(V))  M = V + " n'est pas une e-mail valide";  return M }

function Meta(Ctl, Nom, V) {
	var Cto, S, J, JVar, e, Pg, T, i, L, c, O
	if (TypOf(Ctl)=='object') {
		Cto = Ctl;  Ctl = Cto.Ctrl
	}
	O = LID(Ctl)
	if (!(S=LVal(O)))
		J = {}
	else{
		S = Replace(S,'\r\n','\\n');  S = Replace(S,'\n','\\n');
		J = JSOND(S);  if (!J)  return;     //alert(Nom+crr+S+crr+JSONS(J))
	}
	JVar = J
	if (Nom.indexOf('~')>=0) {
		T = Nom.split('~');  L = T.length - 1
		for (i=0; i<L; i++) {
			Nom = T[i];  if (!JVar[Nom])  JVar[Nom] = {};  JVar = JVar[Nom];
		}
		Nom = T[L]
	}
	if (V===undefined) { V = JVar[Nom];  if (typeof(V)=='object')  V = JSONS(V);  return V }
	if (typeof(V)=='string') { c = (V+'').substr(0,1);  if (c=='{' || c=='[')  V = JSOND(V) }
	if ((Pg=window['debMaj_'+LX(O,'name')])) {
		Opt = { Nom:Nom, V:V }
		if (!(e=Pg(JVar,Opt)))  return
		Nom = Opt.Nom;  V = Opt.V
		//alert(Nom+cr+V+crr+JSW(J))
	}
	if (V)  JVar[Nom] = V;  else  delete(JVar[Nom])
	S = JSONS(J);  if (S=='{}' || S=='[]')  S=''
	if (Cto)  Cto.Val(S);  else  PVal(O,S)
  //alert(S+crr+JSONS(J))
}

function SelectOpt(Ctl) {
	Ctl = LID(Ctl);  if (!Ctl)  return
	if (!Ctl.options || Ctl.selectedIndex<0)  return null
  return Ctl.options[Ctl.selectedIndex];
}

function setComboBox(CB, Liste, Opt) {
	var T, Cod, CodV, S, O, V, N, i, j, ValDef, R, okSel, nb
	CB = LID(CB);  if (!CB)  return
	if (typeof Liste=='string') {
		switch(Liste) {
			case 'SelDat':  Liste = ",(Tous);-0 day,Aujourd'hui;-2 day,3 derniers jours;-6 day,7 derniers jours;-1 month,30 derniers jours;M,Mois en cours;M-1,Mois précédent;-3 month,3 derniers mois;-12 month,12 mois glissants;A,Année en cours;A-1,Année précédente";  break;
		}
		Liste = Tableau2D(Liste);		//alert(JSW(Liste))
	}
	if (Opt==undefined)  Opt={};  else if (!isObj(Opt))  Opt = {Clear:Opt}
	if (Opt.Clear)  CB.innerHTML=''

 	if ((S=LX(CB,'AjDeb'))) { T = Tableau2D(S);  for (i in Liste)  T.push(Liste[i]);  Liste = T }
 	if ((S=LX(CB,'AjFin'))) { T = Tableau2D(S);  for (i in T)  Liste.push(T[i]); }
	//if (CB.name=='OP.CodRub')  alert(JSW(Liste))

	ValDef = Opt.ValDef;  j=0

	for (Cod in Liste) {
		if (Cod=='length')  continue
		R = Liste[Cod];
		if (Opt.Test && !eval(Opt.Test))  continue
		if (Opt.Sauf && Tin(Opt.Sauf,Cod))  continue
		CodV = Cod
		O = document.createElement('OPTION')
		if (Opt.Typ=='obj') {
			V = R[Opt.Lib]
		}else if (typeof(R)=='object') {      // tableaux T[n]={Cle,Libellé}
			i = 0
			for (N in R) {
				S = R[N]
				if (i==0)  CodV = S
				else if (i==1)  V = S
				else{
					PX(O,N,S)
				}
				i++
			}
			if (i<2) { V=CodV;  CodV=Cod  }  // cas des tableaux T[Cle]=Libellé
		}else{
			V = R
		}
		O.value = CodV;  O.text = V
		if (Opt.Sel)  if ((Opt.Sel=='_1_' && j==0) || Opt.Sel==CodV)  O.selected=true;
		CB.add(O,Opt.pos)
		j++
	}
	nb = CB.options.length
	if (nb==1)  ValDef = CodV
	if (ValDef!==undefined)  PVal(CB,ValDef)
}

function Edit_to_Memo() {
	var n, id, inst, S, Ctl, Cto, tiny = App.tinyMCE
	if (!tiny)  return
	tiny.triggerSave();
	for (id in tiny.editors) {
		Ctl = LID(id);  if (Ctl && (Cto=Ctl.Cto)) { Cto.Val(LVal(Ctl));  Cto.Change() }
    //inst = tiny.editors[id];  alert(inst.isNotDirty+crr+inst.getContent())
  }
}

PutValSql = function(Chaine, D, V, Param) {  //Chaine = contact;CodCo;Prenom,Nom;CatCo  D = où placer le résultat, V = code à rechercher, Param.Back = callback
	if (!V)  return
	D = LID(D);  if (!Chaine || D.Code==V)  return
	D.Code = V
	var S, Sql, t
	if (Isole(Chaine,' ',1)=='SELECT') {
		Sql = Replace(Chaine,'$V',V)
	}else{
		t = Chaine.split(';')
		S = 'CONCAT('+Replace(t[2],',',",' ',")+') AS Rep'
		if (t.length>3)  S=S+','+t[3]
		Sql = "SELECT "+S+" FROM "+t[0]+" WHERE "+t[1]+"="+V
	}
	if (!Param)  Param = {}
	Param.Callback = function(re,PM,reJ) {
		var k, JS
		if (reJ && reJ.Data) {
			JS=reJ.Data[0]
			for (k in JS) {
				if (k=='Rep')  D.innerHTML = JS.Rep;  else  D[k] = JS[k];  //alert(k+crr+D[k])
			}
			if (PM.Back)  PM.Back(reJ)
		}
	}
		//alert(Sql)
	ExecAction({Action:'LitSql',Sql:Sql}, Param)
}

// ====================================      ss-PGM     ===============================
function FormeSql(Chaine) {
	var T, Sql
	if (Isole(Chaine,' ',1)=='SELECT')
		Sql = Chaine
	else{
		T = Chaine.split(';')
		Sql = "SELECT " + T[1] + ', ' + T[2] + " FROM " + T[0] + " WHERE " + T[3];		//alert(Sql)
	}
	return Sql
}

KeyDown = function(e) {
	var key, O, P, S
	e = window.event||e;		//alert(ev.keyCode+crr+ev.shiftKey)
	O = EventCtrl(e)
	key = (ie)?event.keyCode:e.which;		//alert(key)
	switch (key) {
		case  13:
			S = LX(O,'type')
			if (O.tagName=='INPUT' && (!S || S=='text' || S=='password') && (P=ElemPClass(O,'Vue'))) {
				var V = P.Vue;
				if (V.Typ=='Rech' || V.ValidByEntree) {
					Cto = O.Cto
					Cto.Change()
					if (V.Valider)  V.Valider();	//alert(Lout(O)+crr+Lout(P))
				}
			}
			break;
	}
}

function ReadBase(cl1, Deep, Call, Opt) {
	var JS = { Action:"ListData", BD:{NomT:'l_base_m', ValCle:cl1, Deep:Deep, Sortie:'JS'} };
	copyObj(JS,Opt)
	ExecAction(JS, function(re, Opt, reJ) {
		var J, T;		//alert(JSW(reJ))
		if (reJ && reJ.retour) {
			J = reJ.Data;  if (Deep==1)  J = J[cl1]
			if (Call)  Call(J)
		}else{
			PHB(re,'ReadBase','JS');
		}
	})
}

