Gérer des formulaires dynamiquement
E. Roumegou

 

 

Comment par programmation générer des formulaires avec un nombre de zones variables ?
Comment exploiter ensuite les valeurs saisies avec WebDev et gérer l'affichage d'une popUp ?

 

C'est ce que nous allons détailler ici.

Voici quelques exemples de ces popup qui évoluent en fonction de ce qui est paramétré dans des tables mySQL.

On personnalise ainsi l'étiquette, le type de la zone, la taille de la saisie, les différentes valeurs de listes etc...

Le principe est simple, on va :
- générer le code du formulaire dans un champs HTML
- passer ce code généré en paramètre à la popup ainsi qu'une commande SQL préformatée pour la fiche.
- utiliser des contrôles javascript.
- mettre à jour la commande SQL en javascript côté navigateur et la repasser à WebDev pour traitement notamment de la mise à jour de la fiche par l'execution de la commande.

1 - ouverture de la popup

soit un lien lienmoderes vsur la page Appelante.

WL Clic (onclick) de lienmodeRes (Navigateur)

SELON NBINFO
CAS 1,2,3,4
NavigateurOuvre("","NOUVNAV",ONSimple+ONDimension, 500, 220)
CAS 5,6,7,8
NavigateurOuvre("","NOUVNAV",ONSimple+ONDimension, 500, 400)
CAS 9,10
NavigateurOuvre("","NOUVNAV",ONSimple+ONDimension, 500, 600)
AUTRE CAS
NavigateurOuvre("","NOUVNAV",ONSimple+ONDimension+ONAscenseur)
FIN

ChangeDestination("NOUVNAV")

NBINFO est un champs caché qui contient le nombre d'infos de saisies que contiendra le formulaire. Cette zone est alimentée d'un précédent traitement qui a affiché le détail des résultats. Selon le nombre, on taillera la fenêtre de façon différente.

Clic de lienmodeRes (serveur)

wch est chaîne=fgMajResultat(RES_ID)
i est un entier
i=LISRES
wHTML,wSQL,wListe est chaîne
wHTML=ExtraitChaîne(wch,1,"§§")
wSQL=ExtraitChaîne(wch,2,"§§")
wListe=ExtraitChaîne(wch,3,"§§")
SI PAS ContexteExiste(MAJRESULT) ALORS
ContexteOuvre(MAJRESULT,wHTML,wSQL,wListe,"RefreshLapage('"+i+"')")
SINON
MAJRESULT.Html1=wHTML
MAJRESULT.sqlcmd=wSQL
MAJRESULT.Flag=1 //ouvert
MAJRESULT.imax=RES_ID=RES_ID
MAJRESULT.imax=ChaîneOccurrence(wListe,TAB)+1
MAJRESULT.lischp=wListe
MAJRESULT.sCodeJS="opener.RefreshLapage('"+i+"')"
FIN
PageActualise(MAJRESULT)

fgMajResultat est la fonction qui va permettre d'agencer le formulaire.
Ensuite, on regarde si la page MAJRESULT (la popUp) existe dèjà en tant que contexte et sinon on ouvre cette page en lui passant les paramètres. Dans le cas où elle existe déjà, on met à jour les champs de cette fenêtre, notamment le champs flag qui est un champs caché qui va nous permettre de gérer la fermeture de la popUp en code navigateur.
Vous noterez aussi la préparation de la procédure RefreshLaPage qui va être executé depuis la popUp.
Le PageActualise(MAJRESULT) provoque ensuite l'affichage de la fenêtre.

 

 

2 - Dans la popup, page MAJRESULT

dans cette page, on retrouve :
- notre champs HTML Html1 qui va contenir notre formulaire
- un champs caché Sqlcmd qui va contenir notre ordre update préformaté
- le champs caché Flag pour gérer la fermeture de la popup.
- le bouton Valider

 

procédure Navigateur

function RefreshLapage(nlig)
{
_C1(nlig);
}

Cette procédure effectue le clic de la table qui provoque le raffraichissement du libellé HTML. Vous aurez trouvé le nom de cette fonction en épluchant le code source généré par WebDev.

 

en code de la page MAJRESULT,

en déclaration globale, on initialise les champs avec nos paramètres.
En onload navigateur, si le code flag est à 2, c'est que l'on est déjà passé et que l'on peut fermer la popup, c'est à dire le navigateur ouvert indépendemment pour cette popup. Au préalable, on execute la procédure Navigateur passée en paramètre (RefreshLapage('i'); i étant le n° de ligne de la table)

function JS_FermeMAJRESULT()
{
eval(sCodeJS);
self.close();
}

On passera ensuite la main au code Fermeture de MAJRESULT (serveur) qui là, va réactualiser notre page appelante.

la fonction fgMajResultat

C'est cette fonction globale qui va générer notre code Html. Je vous la livre dans son intégralité.
Rappel du principe :
Récupération dans des tables mySQL de la description de la saisie.
Préparation des zones formulaires en initialisant aussi par les valeurs courantes. Pour chaque type de zone, on a une chaine de code HTML, avec la description et l'étiquette de la zone et eventuellement les fonctions javascript de contrôle à appeler.
Préparation d'un ordre SQL de type UPDATE PEOPLE_RESULT SET MACOL1=%MACOL1%,MACOL2=%MACOL2% WHERE RES_ID=122
En préparant le formulaire, on substitue par des ChaineConstruit les noms des variables, leur contenu, etc dans les séquences de code HTML
Remarques : Pour accèder aux bases (mySQL), j'utilise les accès alternatifs et ma classe c_GestionSQL, plus d'infos ici
Le copier coller ne fait pas apparaître le code indenté ni la coloration syntaxique. Cela ne rend pas la lecture facile mais vous permettra de recopier ce code.

PROCEDURE fgMajResultat(pId)
lCurReq est un entier
commande est chaîne
NumCol,i,j est un entier
tValNum est un tableau de 15 réels
tLib est un tableau de 27 chaînes
tUse est un tableau de 15 entiers
tValAlpha est un tableau de 12 chaînes
wCh,wCh1,wCh2,wch3,wCh4,wchamp,wchamp2 est chaîne
POD_DESC est chaîne
CodeHTML est chaîne
sqlcmd,colmaj,lischp est chaîne
pod_list_25,pod_list_26,pod_list_27 sont des chaînes
sqlcmd="UPDATE PEOPLE_RESULT SET %1 WHERE RES_ID="+pId

monSQL:RAZ()
monSQL:SetSGBD(gBase)
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL01")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL02")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL03")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL04")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL05")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL06")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL07")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL08")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL09")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL10")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL11")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL12")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL13")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL14")
monSQL:AddSelect("PEOPLE_RESULT.RES_VAL15")
monSQL:AddSelect("PEOPLE_RESULT.RES_LIB16")
monSQL:AddSelect("PEOPLE_RESULT.RES_LIB17")
monSQL:AddSelect("PEOPLE_RESULT.RES_LIB18")
monSQL:AddSelect("PEOPLE_RESULT.RES_DAT19")
monSQL:AddSelect("PEOPLE_RESULT.RES_DAT20")
monSQL:AddSelect("PEOPLE_RESULT.RES_DAT21")
monSQL:AddSelect("PEOPLE_RESULT.RES_BOOL22")
monSQL:AddSelect("PEOPLE_RESULT.RES_BOOL23")
monSQL:AddSelect("PEOPLE_RESULT.RES_BOOL24")
monSQL:AddSelect("PEOPLE_RESULT.RES_STAT25")
monSQL:AddSelect("PEOPLE_RESULT.RES_STAT26")
monSQL:AddSelect("PEOPLE_RESULT.RES_STAT27")
monSQL:AddSelect("PERIOD.POD_LIB_01")
monSQL:AddSelect("PERIOD.POD_LIB_02")
monSQL:AddSelect("PERIOD.POD_LIB_03")
monSQL:AddSelect("PERIOD.POD_LIB_04")
monSQL:AddSelect("PERIOD.POD_LIB_05")
monSQL:AddSelect("PERIOD.POD_LIB_06")
monSQL:AddSelect("PERIOD.POD_LIB_07")
monSQL:AddSelect("PERIOD.POD_LIB_08")
monSQL:AddSelect("PERIOD.POD_LIB_09")
monSQL:AddSelect("PERIOD.POD_LIB_10")
monSQL:AddSelect("PERIOD.POD_LIB_11")
monSQL:AddSelect("PERIOD.POD_LIB_12")
monSQL:AddSelect("PERIOD.POD_LIB_13")
monSQL:AddSelect("PERIOD.POD_LIB_14")
monSQL:AddSelect("PERIOD.POD_LIB_15")
monSQL:AddSelect("PERIOD.POD_LIB_16")
monSQL:AddSelect("PERIOD.POD_LIB_17")
monSQL:AddSelect("PERIOD.POD_LIB_18")
monSQL:AddSelect("PERIOD.POD_LIB_19")
monSQL:AddSelect("PERIOD.POD_LIB_20")
monSQL:AddSelect("PERIOD.POD_LIB_21")
monSQL:AddSelect("PERIOD.POD_LIB_22")
monSQL:AddSelect("PERIOD.POD_LIB_23")
monSQL:AddSelect("PERIOD.POD_LIB_24")
monSQL:AddSelect("PERIOD.POD_LIB_25")
monSQL:AddSelect("PERIOD.POD_LIB_26")
monSQL:AddSelect("PERIOD.POD_LIB_27")
monSQL:AddSelect("PERIOD.POD_USE_01")
monSQL:AddSelect("PERIOD.POD_USE_02")
monSQL:AddSelect("PERIOD.POD_USE_03")
monSQL:AddSelect("PERIOD.POD_USE_04")
monSQL:AddSelect("PERIOD.POD_USE_05")
monSQL:AddSelect("PERIOD.POD_USE_06")
monSQL:AddSelect("PERIOD.POD_USE_07")
monSQL:AddSelect("PERIOD.POD_USE_08")
monSQL:AddSelect("PERIOD.POD_USE_09")
monSQL:AddSelect("PERIOD.POD_USE_10")
monSQL:AddSelect("PERIOD.POD_USE_11")
monSQL:AddSelect("PERIOD.POD_USE_12")
monSQL:AddSelect("PERIOD.POD_USE_13")
monSQL:AddSelect("PERIOD.POD_USE_14")
monSQL:AddSelect("PERIOD.POD_USE_15")
monSQL:AddSelect("PERIOD.POD_REFEXT")
monSQL:AddSelect("PERIOD.POD_DESC")
monSQL:AddSelect("PERIOD.POD_LIST_25")
monSQL:AddSelect("PERIOD.POD_LIST_26")
monSQL:AddSelect("PERIOD.POD_LIST_27")

monSQL:AddWhere("PEOPLE_RESULT.RES_ID="+pId)
monSQL:AddJoin("PEOPLE_RESULT.POD_ID=PERIOD.POD_ID","INNER")
commande=monSQL:Rtv_ReqSQL()
lCurReq=2

SI fSQL:mySQLExec(commande,lCurReq) ALORS
fSQL:mySQLPremier(lCurReq)
TANTQUE PAS fSQL:mySQLEnDehors
NumCol=0
//charge les valeurs dans des tableaux
POUR i=1 A 15
NumCol++;tValNum[i]=fSQL:mySQLCol(lCurReq,NumCol)
FIN
// charge les valeurs alpha

POUR i=1 A 3 // libellés
NumCol++;tValAlpha[i]=fSQL:mySQLCol(lCurReq,NumCol)
FIN
POUR i=4 A 6 //dates
NumCol++;tValAlpha[i]=DateVersChaine(DateSGBD(fSQL:mySQLCol(lCurReq,NumCol),cFromSGBD))
FIN
POUR i=7 A 9 //booléen
NumCol++;tValAlpha[i]=NumériqueVersChaine(fSQL:mySQLCol(lCurReq,NumCol))
FIN
POUR i=10 A 12 //codes stats
NumCol++;tValAlpha[i]=fSQL:mySQLCol(lCurReq,NumCol)
FIN
// charge les libellés
POUR i=1 A 27
NumCol++;tLib[i]=SansEspace(fSQL:mySQLCol(lCurReq,NumCol))
FIN
//charge les fmt
POUR i=1 A 15
NumCol++;tUse[i]=fSQL:mySQLCol(lCurReq,NumCol)
FIN
NumCol++;wCh=fSQL:mySQLCol(lCurReq,NumCol)
NumCol++;wCh2=fSQL:mySQLCol(lCurReq,NumCol)
POD_DESC=wCh+ESP+wCh2
NumCol++;pod_list_25=fSQL:mySQLCol(lCurReq,NumCol)
NumCol++;pod_list_26=fSQL:mySQLCol(lCurReq,NumCol)
NumCol++;pod_list_27=fSQL:mySQLCol(lCurReq,NumCol)
wchamp="pod_list_25"
// si c'est une liste, prépare les balises <option></option>
SI SansEspace({wchamp})<>"" ALORS
wCh=""
POUR i=1 A ChaîneOccurrence({wchamp},";")
wchamp2=ExtraitChaîne({wchamp},i,";")
wCh=wCh+"<option value="""+wchamp2+""">"+wchamp2+"</option>"
FIN
{wchamp}=wCh
FIN
wchamp="pod_list_26"
SI SansEspace({wchamp})<>"" ALORS
wCh=""
POUR i=1 A ChaîneOccurrence({wchamp},";")
wchamp2=ExtraitChaîne({wchamp},i,";")
wCh=wCh+"<option value="""+wchamp2+""">"+wchamp2+"</option>"
FIN
{wchamp}=wCh
FIN
wchamp="pod_list_27"
SI SansEspace({wchamp})<>"" ALORS
wCh=""
POUR i=1 A ChaîneOccurrence({wchamp},";")
wchamp2=ExtraitChaîne({wchamp},i,";")
wCh=wCh+"<option value="""+wchamp2+""">"+wchamp2+"</option>"
FIN
{wchamp}=wCh
FIN

fSQL:mySQLSuivant(lCurReq)
FIN

SINON
fSQL:mySQLMsgBox(commande)
FIN
fSQL:mySQLFerme(lCurReq)

// Formate le champs HTML
//CodeHTML="<form action="""" method=""post"" enctype=""multipart/form-data"" name=""form1"">"+rc+...
CodeHTML="<table width=""480"" border=""2"" cellspacing=""0"" cellpadding=""2"">"+...
"<tr><td><table width=""100%"" border=""0"" cellspacing=""2"" cellpadding=""2""><tr bgcolor=""#CC0000""><td colspan=""2"">"+...
"<div align=""center""><strong><font color=""FFFFFF"">"+POD_DESC+"</font></strong></div></td></tr>"+...
"<tr><td width=""58%""><font size=""2"">&nbsp;&nbsp;</font></td><td width=""42%""><font size=""2"">&nbsp;&nbsp;</font></td></tr>"+RC

// valeur type texte
wCh="<tr><td><font size=""2"">&nbsp;&nbsp;%1</font></td><td><input name=""%2"" type=""text"" value=""%3"" size=""%4"" maxlength=""%5""></td></tr>"
// valeur de type numérique
// case à cocher
wCh2="<tr><td><font size=""2"">&nbsp;&nbsp;%1</font></td><td><input name=""%2"" type=""checkbox"" value=""1"" %3></td></tr>"
// zone de liste
wch3="<tr><td><font size=""2"">&nbsp;&nbsp;%1</font></td><td><select name=""%2"" size=""1""> %3></td></tr>"
SELON Nation()
CAS 3 //anglais
wCh4="<tr><td><font size=""2"">&nbsp;&nbsp;%1</font></td><td><input name=""%2"" type=""text"" onChange=""CtrlDate(this,'Incorrect date')"" value=""%3"" size=""%4"" maxlength=""%5"">&nbsp;&nbsp;(dd/mm/yyyy)</td></tr>"
wCh1="<tr><td><font size=""2"">&nbsp;&nbsp;%1</font></td><td><input name=""%2"" type=""text"" onChange=""CtrlNum(this,'%1 must be a numeric value')"" value=""%3"" size=""%4"" maxlength=""%5""></td></tr>"

CAS 5 // français
wCh4="<tr><td><font size=""2"">&nbsp;&nbsp;%1</font></td><td><input name=""%2"" type=""text"" onChange=""CtrlDate(this,'Date incorrecte')"" value=""%3"" size=""%4"" maxlength=""%5"">&nbsp;&nbsp;(jj/mm/aaaa)</td></tr>"
wCh1="<tr><td><font size=""2"">&nbsp;&nbsp;%1</font></td><td><input name=""%2"" type=""text"" onChange=""CtrlNum(this,'%1 doit être une valeur numérique')"" value=""%3"" size=""%4"" maxlength=""%5""></td></tr>"
FIN
// valeur de type date

colmaj="";lischp=""
//les valeurs
POUR i=1 A 15
wchamp="RES_VAL"+NumériqueVersChaine(i,"02d")
SI tLib[i]<>"" ALORS
CodeHTML+=ChaîneConstruit(wCh1,tLib[i],wchamp,NumériqueVersChaine(tValNum[i]),"14","12")+RC
colmaj+=wchamp+"=%"+wchamp+"%,"
lischp+=wchamp+TAB
//
// selon tuse[i]
// cas 1 // non utilisé
// cas 2 // nbre entier
// CodeHTML+=ChaîneConstruit(wch,tlib[i],wchamp,NumériqueVersChaine(tValNum[i],"10d"),"10")+rc
// cas 3 // avec 2 décimales
// CodeHTML+=ChaîneConstruit(wch,tlib[i],wchamp,NumériqueVersChaine(tValNum[i],"11.2f"),"12")+rc
// FIN
FIN
FIN
//libellé
j=0
POUR i=16 A 18
j++
wchamp="RES_LIB"+NumériqueVersChaine(i,"02d")
SI tLib[i]<>"" ALORS
CodeHTML+=ChaîneConstruit(wCh,tLib[i],wchamp,tValAlpha[j],"32","30")+RC
colmaj+=wchamp+"='%"+wchamp+"%',"
lischp+=wchamp+TAB
FIN
FIN
//Dates
POUR i=19 A 21
j++
wchamp="RES_DAT"+NumériqueVersChaine(i,"02d")
SI tLib[i]<>"" ALORS
CodeHTML+=ChaîneConstruit(wCh4,tLib[i],wchamp,tValAlpha[j],"12","10")+RC
SELON gBase
CAS cMYSQL
colmaj+=wchamp+"=str_to_date('%"+wchamp+"%','%d/%m/%Y')," //dispo qu'à partir de 4.1
CAS cORACLE
colmaj+=wchamp+"=to_date('%"+wchamp+"%','YYYY-MM-DD'),"
FIN
lischp+=wchamp+TAB
FIN
FIN
//booleen
POUR i=22 A 24
j++
wchamp="RES_BOOL"+NumériqueVersChaine(i,"02d")
SI tLib[i]<>"" ALORS
SI tValAlpha[j]<>"1" ALORS
CodeHTML+=ChaîneConstruit(wCh2,tLib[i],wchamp,"unchecked")+RC
SINON
CodeHTML+=ChaîneConstruit(wCh2,tLib[i],wchamp,"checked")+RC
FIN
colmaj+=wchamp+"=%"+wchamp+"%,"
lischp+=wchamp+TAB
FIN
FIN
//Stats
POUR i=25 A 27
j++
wchamp="RES_STAT"+NumériqueVersChaine(i,"02d")
wchamp2="pod_list_"+NumériqueVersChaine(i,"02d")
SI tLib[i]<>"" ALORS
SI {wchamp2}<>"" ALORS
// zone liste
SI tValAlpha[j]<>"" ALORS
// renseigné, initier la valeur
{wchamp2}=Remplace({wchamp2},"<option value="""+tValAlpha[j]+""">"+tValAlpha[j]+"</option>",...
"<option value="""+tValAlpha[j]+""" selected>"+tValAlpha[j]+"</option>")
FIN
CodeHTML+=ChaîneConstruit(wch3,tLib[i],wchamp,{wchamp2})+RC
SINON
// zone normale
CodeHTML+=ChaîneConstruit(wCh,tLib[i],wchamp,tValAlpha[j],"17","15")+RC
FIN


colmaj+=wchamp+"='%"+wchamp+"%',"
lischp+=wchamp+TAB
FIN
FIN
//CodeHTML+="</table></tr></table></form>"
CodeHTML+="</table></tr></table>"
colmaj=TronqueDernierCaractere(colmaj)
lischp=TronqueDernierCaractere(lischp)

RENVOYER CodeHTML+"§§"+ChaîneConstruit(sqlcmd,colmaj)+"§§"+lischp

Le Bouton Valider

 

WL Clic (onclick) deBouton1 (Navigateur)

i est un entier

POUR i=1 A imax
sqlcmd=Remplace(sqlcmd,"%"+ExtraitChaîne(lischp,i)+"%",... JSPropriété("document.MAJRESULT."+ExtraitChaîne(lischp,i),"value"))
FIN

LISCHAMP contenant la liste de nos Zones de formulaires, on va par une boucle remplacer les %var% par le contenu de ces variables; ceci par la fonction JSPropriété avec value.

Clic de Bouton1 (serveur)

SI Position(gBaseVersion,"4.0.")>0 ALORS // on part du principe que l'on est en 4.0 minimum, sinon
// on est en 4.1.1 ou +
// verrue à cause de dates : la fn str_to_date n'étant dispo qu'à partir de mysql 4.1
// il va falloir redisposer les dates avant l'ordre sql car ce dernier ne sera pas interprêté.
// après la saisie, elles reviennent sous forme jj/mm/AAAA
   datjma est chaîne
   TANTQUE Position(sqlcmd,"str_to_date")>0
      datjma=ExtraitEntre(sqlcmd,"=str_to_date('","','%d/%m/%Y')")
      sqlcmd=Remplace(sqlcmd,"=str_to_date('"+datjma+"','%d/%m/%Y')","='"+Droite(datjma,4)+"-"+Milieu(datjma,4,2)+"-"+Gauche(datjma,2)+"'")
   FIN
FIN

SI PAS fSQL:mySQLExec(sqlcmd,0) ALORS
   Erreur("Les valeurs que vous avez indiquées ne sont pas correctes"+RC+"Veuillez recommencer SVP")
   sqlcmd=pSQL // restaure la commande d'origine
   Flag=1 // le navigateur ne sera pas fermé
SINON
   Flag=2 // okay pour fermer la page
FIN
fSQL:mySQLFerme(0)

La première partie du traitement est nécessaire pour le traitement des dates qui doit se trouver en YYYY-MM-DD en mySQL. Cela ne peut se gérer par la commande SQL qu'à partir de la version 4.1, d'où le test.
Une fois que l'on est Ok, on execute la commande de mise à jour; on peut alors fermer la page et on met donc le flag à 2. On reviendra dans la page appellante par le code Serveur Fermeture.

 

Les fonctions Javascript

function CtrlDate(objet,msgerr)
{
with (objet) // Pour l'objet en paramètre
{
valeur=objet.value
if (isDate(value)) // Si valeur est pas une date correcte
{
return true;
}
else
{
if (msgerr!="") {alert(msgerr);}
objet.select(); // Resélectionne le champ
objet.focus(); // Resélectionne le contenu
return false;
}
}
}
function CtrlNum(objet,msgerr)
{
with (objet) // Pour l'objet en paramètre
{
valeur=parseInt(value);
if (isNaN(valeur)) // Si valeur n'est pas numérique
{
if (msgerr!="") {alert(msgerr);}
objet.select(); // Resélectionne le champ
objet.focus(); // Resélectionne le contenu
return false;
}
else
{
return true;
}
}
}
unction isDate(d)
{
// Cette fonction permet de vérifier la validité d'une date au format jj/mm/aa ou jj/mm/aaaa
if (d == "") // si la variable est vide on retourne faux
return false; e = new RegExp("^[0-9]{1,2}\/[0-9]{1,2}\/([0-9]{2}|[0-9]{4})$");

if (!e.test(d)) // On teste l'expression régulière pour valider la forme de la date
return false; // Si pas bon, retourne faux

// On sépare la date en 3 variables pour vérification, parseInt() converti du texte en entier
j = parseInt(d.split("/")[0], 10); // jour
m = parseInt(d.split("/")[1], 10); // mois
a = parseInt(d.split("/")[2], 10); // année

// Si l'année n'est composée que de 2 chiffres on complète automatiquement
if (a < 1000) {
if (a < 89) a+=2000; // Si a < 89 alors on ajoute 2000 sinon on ajoute 1900
else a+=1900;
}

// Définition du dernier jour de février
// Année bissextile si annnée divisible par 4 et que ce n'est pas un siècle, ou bien si divisible par 400
if (a%4 == 0 && a%100 !=0 || a%400 == 0) fev = 29;
else fev = 28;

// Nombre de jours pour chaque mois
nbJours = new Array(31,fev,31,30,31,30,31,31,30,31,30,31);

// Enfin, retourne vrai si le jour est bien entre 1 et le bon nombre de jours, idem pour les mois, sinon retourn faux
return ( m >= 1 && m <=12 && j >= 1 && j <= nbJours[m-1] );
}

(