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 (Ctl.parentNode.tagName=='DIV')  this.Contener = Ctl.parentNode
		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'))) {
			j = JST(S)
			if (j.Sql) j.Sql = FormeSql(j.Sql)
			this.setCB(j)
		}
		//this.ChampSuite()
//		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
	if ((S=this.Contener))  RMNod(S);  else  RMNod(Ctl)
}

CtlClass.prototype.ValDef = function(Opt) {
	var V, S, Ctl, Ch
	Ctl = this.Ctrl;		//alert(Lout(Ctl))
	if (!Opt)  Opt = {}
	if (!Opt.sansMeta) {
		if (S=LX(Ctl,'meta')) {
			//if ((Ch=this.Fo.Ctrls[S]))  PVal(Ctl, Meta(Ch, this.Nom))
			//wh("ValDef: "+this.Nom+', meta='+S+', '+this.Fo.all['Descript'])
			if ((Ch=this.Fo.all[S])) {
				V = Meta(Ch.Ctrl, this.Nom)
				PVal(Ctl, V)
				//wh("ValDef: "+this.Nom+', meta='+S+', V='+V)
			}
		}else{
			if (this.Typ2=='meta') {
//alert(this.Nom+crr+LVal(this.Nom)+crr+this.Val()+crr+this.V)
			}
		}
	}
	V = LVal(Ctl)
	Ch = this.Champ
	//if (Ch.Nom=='hTyp') { 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
			}
		  //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.ChangeMeta = function() {
	var Nom, Cto, Fo = this.Fo
	//alert(this.Nom+crr+this.Val())
	for (Nom in Fo.all) {
		Cto = Fo.all[Nom];
		if (Cto && LX(Cto.Ctrl,'meta')==this.Nom) {
			V = Meta(this.Ctrl, Cto.Nom);
			PVal(Cto.Ctrl, 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 = null
	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, V
	Ctl = this.Ctrl
	V = Ctl.chSo.Val()
	if ((S=LX(Ctl,'Data'))) {
		S = Replace(S,'ValSo',V)
		if (S.substr(0,1)=='=') {
			J = eval(S.substr(1))
		}else
			J = JSOND(S)
		if (J) {
			S = J[V];		//alert(JSW(J))
			this.setCB(S,1)
		}
	}else if ((Sql=FormeSql(LX(Ctl,'Sql')))) {
		Sql = Replace(Sql,'chSo',V)
		Sql = Replace(Sql,'ValSo',V)
		Sql = ReplaceVar(Sql);		//alert("Traite"+crr+Sql)
		this.setCB({Pgm:"LitSql",Sql:Sql},{Clear:1})
	}
}

CtlClass.prototype.ChampSuite = function() {
	var O, S, V
	if (!(S=LX(this.Ctrl,'chSuit')))  return
	O = this.Fo.getCtl(S)
	if (!(V=this.Val())) { //Hide(O,'DIV');
		if (O.Cto)  O.Cto.Val('');  return }
	if (S==LX(O,'ValSo'))  alert(S)
	if (S==LX(O,'ValSo'))  return
	//if (V)  Aff(O,'DIV');
	PX(O,'ValSo',V);  PX(O,'HideSi0',1);
	if (O.Cto) {
		O.chSo = this
		O.Cto.Traite()
	}
}

CtlClass.prototype.Change = function() {
	var Cto, Ctl, S, V, O;      //alert(Lout(this.Ctrl))
	V = this.Format()
	this.Val(V)
	Ctl = this.Ctrl
	this.ChampSuite()
// 	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(2)
	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() {  // Met à jour le champ meta en fonction de this.V
	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) {
	// Liste='{Pgm:"LitSql",NomT:"prodrub"}'   ou   =App.CB.Banque  ou  {Pgm:"LitSql",NomT:"base",Sql:"SELECT Ref, Titre FROM l_base WHERE clp=116"}
	// Liste=',(?);08,08;09,09'
	// Liste=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 (isStr(Liste)) {
			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(Put) {
	var O,  Ctl = this.Ctrl
	if (hasClass(Ctl,'Tiny')) {
		if (Put==1 || this.Fo.Oper=='Ajout') {
			var cf = this.Fo.all.Conf;
			if (!(cf && cf.Val() & 8))  this.Tiny()
		}else
			this.noTiny()
	}
// 	if (App.tinyMCE && hasClass(Ctl,'mceEditor')) {
// 		if ((O=tinyMCE.getInstanceById(Ctl.id || this.Nom))) {
// 			O.load()
// 		}
// 	}
}

CtlClass.prototype.Tiny = function() {
	if (!App.tinyMCE)  tiny_setup()
	var Ctl = this.Ctrl,  S = getID(Ctl)
	if (LX(Ctl,'Tiny'))  this.noTiny()
	PX(Ctl,'Tiny',1)  //Ctl.Tiny = tinyMCE.get(S)
	setTimeout(function() {
		var i = (hasClass(Ctl,'mceLiteEditor')) ? 0:1
		tinyMCE.settings = tinyConfigs[i];
		tinyMCE.execCommand('mceAddControl', false, S)
	},80)
}

CtlClass.prototype.noTiny = function() {
	if (!App.tinyMCE)  return
	var S = getID(this.Ctrl)
	RX(this.Ctrl,'Tiny')
	tinyMCE.execCommand('mceRemoveControl', false, S)
}

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); },350); }
	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) },300); }
	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.MemoChamps = function() {
	this.sovV = this.Url(1)
}

TableClass.prototype.onAjout = function() {
	var JD, S,  J = this.sovV,  T = this.all,  C = T[this.NomC],  C1 = T.cl1
	if (this.BD && (JD=this.BD.defTree))  C1 = this.NomC
	if (!J || !C1 || !J[this.NomC])  return
	if (JD) {
		T[JD.TLien].Val(J[C1])
	}else{
		T.clp.Val(J.cl1);  if (T.TypL)  T.TypL.Val(J.TypL);  if (T.Droit)  T.Droit.Val(J.Droit);
	}
	//alert(JSW(J))
}

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)
		if (Cto.Typ2=='meta')  Cto.ChangeMeta()
		Ch.oldV	= Ch.V
		if (Cto)  Cto.finInit(1)
	}
	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) {
	//alert(JSW(reJ)+crr+re)
	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.retour) { S = "La suppression n'a pas fonctionné";  if (reJ.Msg)  S+=crr+reJ.Msg;  alert(S);  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,  Ctl = Cto.Ctrl, fait=0
	if (LX(Ctl,'Tiny'))  Cto.noTiny()
	if (isObj(siVal)) { V = siVal[this.Nom];  if (V==undefined) V='';  fait = 1 }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 (!fait && siVal!==0)  Cto.ValDef()
	//if (this.Nom=='Descript') { a=11	}
	Cto.finInit(0)
}

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 (Cto)  Cto.ChampSuite()
	if (T.Fo.Vue)  T.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, S
	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]
	if (!PosPath(this, 'AffCle'))  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, DD, Stay, K, J, D = this.Div,  Fo = this.Fo,  nb=0
	if ((Stay=$E('.stay',D)))  LID('ifmDiv').appendChild(Stay)
	Fo.Destroy(D,1);  D.innerHTML = '';  this.nbL = 0
	J = PosPath(this, 'Style.Global') || {};  J.Class = 'gridT'
	this.DivT = MakeDom('div',D, J)
	if (Fo.Droit>4) {
		DD = MakeDom('div',this.DivT, {Class:'gridTR gridHead'})
		TR = MakeDom('div',DD, {Class:'Title'},this.Titre)
		TR = MakeDom('div',DD, {Class:'Ico'})
		//$(TR).append("<img title=Exporter src=/biblio/img/action/printer.png> ")
		if (this.icoDisk)  $(TR).append("<img title=Sauvegarder src=/biblio/img/ext/save.gif> ")
		$(TR).append("<img title=Supprimer src=/biblio/img/ext/delete.gif>")
		//$(TR).append("<button onclick='Fos.all.ListPrd.Sov()'>OK</button>&nbsp;")
		//$(TR).append("<button title='supprimer les fiches cochées'>Supprimer</button>")
	}
	J = this.Data
	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
	}
	MakeDom('div',D, {Class:'gridTR gridBas'})
	Fo.InitFo(D)
	this.onAff()
	if (Stay)  D.appendChild(Stay)
	//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 gridTRH'})
	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() {
		$('[name]',TD).each(function() {
			var Name = (this.name || Nom)
			//this.name = Name+'_'+nbL;		//alert(Lout(this))
			PX(this,'name',Name+'_'+nbL)
			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 ((S=this.adData)) {
		$.getJSON(RootSite+'/'+S, function(JS) {
			Me.allData = JS
			Me.Data = JS && JS.Data || {}
			Me.AffGrid()
		})
		return
	}
	if (Fo.foParent && !(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.getData = function() {
	var TJ=[],  Fo = this.Fo,  T = Fo.Table
	$('.gridData',Fo.Div).each(function() {
		var JD, k,  DI={},  nbL = '_'+LX(this,'nbL')
		JD = T.Url(1,this);
		for (k in JD)  DI[k.substr(0,k.length-nbL.length)] = JD[k]
		TJ.push(DI)
	})
	return TJ
}

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,  NomC, Ch, Lien, S, Msg='', ValCle, JS, JD, nbL, DI, TJ=[]
	if (!Me.adData && !(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 }
	if (Me.adData) {
// 		$('.gridData',Fo.Div).each(function() {
// 			DI={};  nbL = '_'+LX(this,'nbL')
// 			JD = T.Url(1,this);
// 			for (k in JD)  DI[k.substr(0,k.length-nbL.length)] = JD[k]
// 			TJ.push(DI)
// 		})
		Me.allData.Data = Me.getData()
		S = "Pgm=SovFic&Path="+Me.adData+"&Txt="+ encodeURIComponent(JSONS(Me.allData)) + AjUrl
		XmlPost(S,'',function(re,S,reJ) {		//alert(JSW(reJ)+crr+re)
			alert(reJ.Msg)
		})
	}else{
		$('.gridVerif',Fo.Div).each(function() {
			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 (hasNod(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 (G.adData)  return
	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 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))) {
		if (!V)  return
		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]) { if (!V)  return;  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(V+crr+S+crr+JSONS(J)+crr+JSW(J)+crr+Lout(O))
}

function SelectOpt(Ctl) {
	Ctl = LID(Ctl);  if (!Ctl)  return
	if (!Ctl.options || Ctl.selectedIndex<0)  return null
  return Ctl.options[Ctl.selectedIndex];
}

function CBData(Ctl, Nom, Opt) {  // Un SELECT avec setCB='=App.CB.CodRub' va exécuter la 1°x son Sql et la 2°x ses données
	var Sql, S, CB
	CB = PosPath(App.CB, Nom)
	if (CB.Sql) {
		Sql = FormeSql(CB.Sql)
		ExecAction({Action:'LitSql',Sql:CB.Sql}, function(re,S,reJ){	//alert(JSW(reJ)+crr+re)
			if (!reJ.retour) { alert("Erreur de requête");  return }
			App.CB[Nom] = reJ.Data
			setComboBox(Ctl, reJ.Data, Opt)
		})
	}else{
		setComboBox(Ctl, CB, Opt)
	}
}

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]
			// Place Rep dans inner et le reste en variables de D
			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     ===============================

