⇧
Bac a sable WEBMO - 12/03/2026 17:30:41
var $numproc; $commande; $i : Integer
var $o; $oo : Object
var $c : Collection
If (Count parameters=0)
//APPELER WORKER("WK_Services";"initProcessWorker")
//$bool:=Lire activation assertions
// $x:=""
// UserIDentification ("EnregistrerIdentifiants";->$x)
// APPELER WORKER("WK_Services";Inscrire au Journal;"Ouvrir_BDD";0;0;0;$x)
$numproc:=New process(Current method name; 0; "tester"; Current process)
Else
cs._CommunFunctions.me.InitProcess()
$o:=New object
$oo:=New object
$c:=New collection
$c:=New collection(0; 31)
//$c:=New collection(2)
//$c:=New collection(0; 3)
$commande:=0
For each ($i; $c)
$commande:=$commande ?+ $i
End for each
If ($commande ?? 0)
// afficher la console de l'application
var $params : Object
$params:=New object
$params.Commande:="Afficher"
$params.sourceLogs:=ALV BDD mère
$params.wndTitre:="Logs application ALV"
cs.xSDK.ResourceALV.me.SetObjet(Est Ressource APP; "Ressources_Communes/nbrMaxLogs"; Is longint; $params; "nbrMaxLogs")
cs.xSDK.EvenementsALV.me.AfficherEditeur($params)
cs._Trace.me.EnvoyerMessages([msgk_event; msgk_log]; "WK libellé 1"; Current method name; "test ALB : WK description 1")
End if
If ($commande ?? 1)
cs._composant.new().InstallerServeur()
cs.$serveur.new().Demarrer()
$c:=WEB Server list
End if
If ($commande ?? 2)
//cs._maintenance.new().CréerBDDmobile()
End if
If ($commande ?? 3)
cs.xALB._maintenance.new().Démarrer()
cs._maintenance.new().InstallerAlbums()
// lire la présence de la tâche du composant ALB et son état
$c:=cs.xSDK.RegistreTaches.new().LireInscriptions()
End if
If ($commande ?? 31)
cs.xSDK.TraductionsEditeur.new().ModifierTraductions()
End if
End if
⇧
WEBMO_EcrireElement - 28/10/2025 18:37:02
Disponible via les balises HTML et les URLs 4D (4DACTION...)
Capable de process préemptif
#DECLARE($url : Text)->$result : Text
var $serveur : cs.$serveur
var $albums : cs.$albums
// dans l'ordre !
Case of
: ($url="@WebALB@")
// ici une requête d'album
// attention le nom de la function peut être dans cs.$albums
$albums:=cs.$albums.new($url)
Case of
: ($albums.url="")
: (OB Is defined($albums; $albums.url))
// url reconnue, lancer la function locale
$result:=$albums[$albums.url]()
: (OB Is defined($albums.webALB; $albums.url))
// url du composant ALB, lancer la function
$albums.webALB[$albums.url]()
$result:=$albums.webALB.result.resultat
: (OB Is defined($albums.reqALB; $albums.url))
// url du composant ALB, lancer la requête
$albums.reqALB[$albums.url]()
// ALB a fait l'envoi
End case
Else
// traiter une url envoyée par un formulaire en construction
$serveur:=cs.$serveur.new()
Case of
// les url XXXXX/nomClasse/nomFunction?params renvoie un text dans $result
// la classe $pagenomClasse doit exister
: ($serveur.TraiterURLpage($url))
// renvoyer le résultat
$result:=$serveur.result.resultat
// les url XXXXX/nomClasse/nomFunction?params renvoie directement un text par WEB SEND TEXT
// ici nomClasse = ACTION toujours
: (cs.$action.new().TraiterURL($url))
// action traitée
End case
End case
⇧
traceHandler - 25/10/2025 09:10:41
Capable de process préemptif
cs._Trace.me.Intercepter()
⇧
ExecuteFunctionPreemptive - 18/10/2025 19:26:20
Capable de process préemptif
#DECLARE($classe : Object; $params : Object)->$numProc : Integer
var $nomTache : Text
var $data : Object
var $trace : cs._Trace
$trace:=cs._Trace.me
$numProc:=0
Case of
: (Not(OB Is defined($params; "functionID")))
$trace.EnvoyerMessages([msgk_event; msgk_log]; "Initialisation :"; Current method name; "'functionID' n'est pas défini dans $params")
: (Value type($params.functionID)#Is text)
$trace.EnvoyerMessages([msgk_event; msgk_log]; "Initialisation :"; Current method name; "'$params.functionID' n'est pas un texte")
: (Not(OB Is defined($params; "nomTache")))
// nécessaire pour tuer la tâche
$trace.EnvoyerMessages([msgk_event; msgk_log]; "Initialisation :"; Current method name; "'nomTache' n'est pas défini dans $params")
: (Not(OB Is defined($params; "numProcessAppelant")))
$trace.EnvoyerMessages([msgk_event; msgk_log]; "Initialisation :"; Current method name; "'numProcessAppelant' n'est pas défini dans $params")
: ($params.numProcessAppelant=-1)
$nomTache:=$params.nomTache
// supprimer la tâche existante
cs.xSDK.RegistreTaches.new().Tuer($nomTache)
// créer le nouveau process
$params.numProcessAppelant:=Current process
$numProc:=New process(Substring(Current method name; Position("."; Current method name)+1); 0; "$WEBMO_process_"+$nomTache; $classe; $params; *)
Else
// c'est ok
// construire la classe
$data:=$classe.new()
If ($data[$params.functionID]#Null)
// créer la tâche associée
// numProcessAppelant est nécessaire pour tuer toutes les tâches d'un même process
$params.tache:=cs.xSDK.RegistreTaches.new().Inscrire(New object("nomProcess"; Current process name; "nomTache"; $params.nomTache; "numProcessAppelant"; $params.numProcessAppelant))
// lancer le traitement demandé
$data[$params.functionID]($params)
// désinscrire la tâche 'nomTache'
$params.tache.DésInscrire()
Else
$trace.EnvoyerMessages([msgk_event; msgk_log]; "Initialisation :"; Current method name; "La classe "+$classe.name+" n'est pas de function "+$params.functionID)
End if
$numProc:=Current process
End case
⇧
COMPILER_WEB - 07/09/2025 12:46:08
wwwRacineRessources:="../../"
⇧
[class]Communes - 30/10/2025 17:08:08
// attributs de la classe
property nom : Text
property ChampsExposés : Collection
property blason : Picture
Class extends _WEBMO_DataStore
Class constructor($IDentité : Variant)
Super("Communes"; $IDentité)
Function FixerParametresListe()->$result : Object
$result:=New object
$result.DataClassNom:="Communes"
$result.Requete:="id>0"
$result.nomFunction:="AfficherFORMdetail"
$result.nomFORMlist:="detailSimple"
Function CreerBDDentity()->$result : Object
$result:=New object
$result.IDunique:=This.IDunique
$result.Elementliste:=This.Elementliste()
// les champs calculés
Super.CreerBDDentity($result; ["Champ_1"; "Champ_2"; "Champ_3"; "Champ_4"; "Champ_5"; "Champ_boutonLibelle_1"; "Champ_boutonLibelle_2"; "Champ_titreIconed_1"; "Champ_titreIconed_2"; "Champ_titreIconedLinked_1"; "Champ_titreIconedLinked_2"; "Champ_titreIconedLinked_3"])
Function labelDataClass()->$result : Text
$result:=Super.labelDataClass("la ")
Function Administration()->$result : Text
// département, région et pays
$result:=This.dataClass.leDepartement.Libellé(New object("Options"; 0x00C90000))
// ----------------------
//MARK:Sélection
// ----------------------
Function LesEvents()->$result : Object
var $c : Collection
$c:=This.dataClass.LesEvents()
$result:=cs.EventsSelect.new($c)
$result.Créer()
Function LesMedias()->$result : Object
// créer la collection des medias
$result:=cs.MediasSelect.new(This.dataClass.LesMedias())
$result.Créer()
Function LesSites()->$result : Object
// créer la collection des medias
$result:=cs.SitesSelect.new(This.dataClass.LesSites())
$result.Créer()
// ----------------------
//MARK: FORM Liste
// ----------------------
Function Elementliste()->$result : Text
$result+="<article id='"+This.IDunique+"' class='element-listeEntity' nom='"+This.nom+"'>"
$result+="<article>"
$result+=This.LibelléLié(This._tagUrl+"WebDATA/<!--#4DEVAL $1.nomFunction-->?<!--#4DEVAL $1.nomFORMlist-->?Communes?"+This.IDunique; New object("Options"; 0))
$result+="</article>"
$result+="<article><span>"
$result+=This.Administration()
$result+="</span></article>"
$result+="</article>"
// ----------------------
//MARK: FORM Detail
// ----------------------
Function Champ_1()->$result : Text
$result:=This.getBlasonURL(This.nomFichierIcone)
Function Champ_2()->$result : Text
$result:=This.nom
Function Champ_3()->$result : Text
$result:=This.Administration()
Function Champ_4()->$result : Text
// rappel : un lieu type 60700 existes pour toutes les communes
// il sert de commentaire à la commune
var $entité : cs.Lieux
var $ID : Integer
$result:=""
$ID:=This.dataClass.LieuParDefaut()
$entité:=cs.Lieux.new($ID)
$result:="<p>"+$entite.commentaire+"</p>"
Function Champ_5()->$result : Text
var $selection : cs.DicoDesNomsSelect
$selection:=This.LesEvents().LesProtagonistes().LesPatronymes()
$result:=$selection.Ecrire()
Function Champ_boutonLibelle_1()->$result : Text
$result:="16829.svg"
Function Champ_boutonLibelle_2()->$result : Text
$result:=Localized string("145")
Function Champ_titreIconed_1()->$result : Text
$result:="16830.svg"
Function Champ_titreIconed_2()->$result : Text
$result:=Localized string("151")
Function Champ_titreIconedLinked_1()->$result : Text
$result:="16831.svg"
Function Champ_titreIconedLinked_2()->$result : Text
$result:=Localized string("152")
Function Champ_titreIconedLinked_3()->$result : Text
$result:="16827.svg"
// -----------------------------
// MARK:Maintenance
// -----------------------------
Function CréerBlasonMobile($dossier : 4D.Folder)
var $pict : Picture
var $cheminFichier : Text
$pict:=This.blason
If (Picture size($pict)=0)
READ PICTURE FILE(Folder(Get 4D folder(Current resources folder); fk platform path).folder("Images").folder("HTML").file("blason_ico.png").platformPath; $pict)
End if
// * créer son imagette Webinée
// largeur max de l'image, hauteur max de l'image
This.cFct.RetaillerImage(->$pict; WebMob Icon largeur; WebMob Icon hauteur)
// ajouter le fichier image au dossier
$cheminFichier:=$dossier.file(This.nomFichierIcone).platformPath
WRITE PICTURE FILE($cheminFichier; $pict; WebMob Icon format)
Function get nomFichierIcone()->$result : Text
$result:="blason_ico.png"
Case of
: (Not((Storage.System.estExécutéDansHôte)))
: (Picture size(This.blason)=0)
Else
$result:=String(This.IDcodé())+"_ico"+WebMob Icon format
End case
Function getBlasonURL($nomFichier : Text)->$result : Text
$result:="../../ressources/Images/mobileData/"
Case of
: (Not(Storage.System.estExécutéDansHôte))
: (Picture size(This.blason)=0)
Else
$result:=This.document.getDataURL()
End case
$result+=Localized string("150")+"/"+$nomFichier
⇧
[class]_document - 19/02/2026 13:12:19
Class constructor()
Function getAppWorkSpaceFolder()->$result : Object
$result:=Storage.Host.$document.call(Null).GetAppWorkSpace()
Function getDataServeurFolder()->$result : Object
$result:=Storage.Host.$document.call(Null).getDataServeurFolder()
//------------------
//mark: installation
//------------------
Function getSessionFolder()->$result : Object
// le dossier de la session Web
$result:=This.getRacineHTMLFolder().folder(Localized string("129")).folder(Session.id)
Function getRacineHTMLFolder()->$result : 4D.Folder
var $texte : Text:=""
Case of
: (Not(cs.xSDK.ResourceALV.me.SetVariable(Est Ressource WEBMO; "Serveur_web/nomDossier_RacineWeb"; Is text; ->$texte)))
: (Storage.System.typeApplication=ALV Client APP)
// filtrer (pas concerné pour l'instant)
: (Storage.System.typeApplication=ALV Serveur APP)
// ouverture de l'APP serveur
$result:=Folder(Structure file(*); fk platform path).parent.parent.parent.parent.folder($texte)
: (Storage.System.typeApplication=ALV Serveur HTTP)
// ouverture du projet avec un 4D serveur non compilé
// dossier dans les document utilisateur
$result:=Folder(fk documents folder).parent.folder("Sites").folder($texte)
: (Storage.System.typeApplication=ALV BDD mère)
// composant dans la base mère
// dossier dans les document utilisateur
$result:=Folder(fk documents folder).parent.folder("Sites").folder($texte)
Else
// composant exécuté seul
$result:=Folder(Structure file(*); fk platform path).parent.parent.parent.folder($texte)
End case
// au besoin, créer le dossier
$result.create()
Function getCertificatSSLFolder()->$result : 4D.Folder
// fixe le chemin du dossier des certificats SSL du serveur Web
var $texte : Text:=""
Case of
: (Not(cs.xSDK.ResourceALV.me.SetVariable(Est Ressource WEBMO; "Serveur_web/nomDossier_CertificatSSL"; Is text; ->$texte)))
: (Storage.System.typeApplication=ALV Client APP)
// hors sujet
$result:=Null
Else
// serveurs APP ou HTTP
// le dossier des cert est au même niveau que le dossier racine HTML
$result:=This.getRacineHTMLFolder().parent.folder($texte)
Case of
: ($result.exists)
// c'est bon
: ($result.create())
// c'est créé
Else
$result:=Null
End case
End case
Function CertInformations()->$result : Object
var $params : Object
$params:=New object("CertificatSSLFolderPath"; This.getCertificatSSLFolder().platformPath)
cs.xSSL.$lectureCERT.new().getInformations($params)
$result:=$params.infos
Function getMobileWebFolder()->$result : 4D.Folder
Case of
: (Storage.System.typeApplication=ALV Serveur APP)
$result:=Folder(fk data folder; *).folder("mobileWeb")
: (Storage.System.typeApplication=ALV BDD mère)
$result:=cs.xSDK.Traces.new().GetGarbageDossier().folder("_WEBMOdebug").folder("mobileWeb")
End case
// au cas ou
$result.create()
// -----------------------------
// MARK:BDD
// -----------------------------
Function getBDDFolder()->$result : 4D.Folder
// installation : dossier des fichiers BDD pour le composant (nomDossier ID_155)
Case of
: (Storage.System.typeApplication=ALV Serveur APP)
// cas opérationnel
$result:=This.getDataServeurFolder().folder(Localized string("156"))
$result.create()
: (Storage.System.typeApplication=ALV BDD mère)
// pour test local
$result:=cs.xSDK.Traces.new().GetGarbageDossier().folder("_WEBMOdebug").folder(Localized string("156"))
$result.create()
Else
// rien
$result:=Null
End case
// -----------------------------
// MARK:Medias
// -----------------------------
Function getMediasFolder()->$result : 4D.Folder
$result:=This.getDataFolder().folder(Localized string("147"))
// au cas ou
$result.create()
Function getVignettesFolder()->$result : 4D.Folder
$result:=This.getDataFolder().folder(Localized string("148"))
// au cas ou
$result.create()
Function getBlasonsFolder()->$result : 4D.Folder
$result:=This.getDataFolder().folder(Localized string("150"))
// au cas ou
$result.create()
Function getDataFolder()->$result : 4D.Folder
// installation : dossier des medias pour le composant (nomDossier ID_155)
Case of
: (Storage.System.typeApplication=ALV Serveur APP)
// cas opérationnel
$result:=This.getDataServeurFolder().folder(Localized string("155"))
$result.create()
: (Storage.System.typeApplication=ALV Serveur HTTP)
// 4D Server pour debug
$result:=cs.xSDK.Traces.new().GetGarbageDossier().folder("_WEBMOdebug").folder(Localized string("155"))
$result.create()
: (Storage.System.typeApplication=ALV BDD mère)
// pour test local
$result:=cs.xSDK.Traces.new().GetGarbageDossier().folder("_WEBMOdebug").folder(Localized string("155"))
$result.create()
Else
// rien
$result:=Null
End case
Function getServeurDataFolder()->$result : 4D.Folder
// serveur Web : en opérationnel, racine du site
$result:=This.getRacineHTMLFolder().folder(Localized string("149"))
// au cas ou
$result.create()
// -----------------------------
// MARK:Albums
// -----------------------------
Function getWEBalbumsFolder()->$result : Object
// (v6.4.6 dans le dossier Web)
$result:=This.getRacineHTMLFolder().folder("Albums")
// -----------------------------
// MARK:URL
// -----------------------------
Function getVignetteNom($ID : Integer)->$result : Text
$result:="vignette_"+String($ID; "00000")+WebMob Icon format
Function getVignetteURL($ID : Integer)->$result : Text
If (Storage.System.estExécutéDansHôte)
$result:=This.getDataURL()
Else
$result:="../../ressources/Images/mobileData/"
End if
$result+=Localized string("148")+"/"+This.getVignetteNom($ID)
Function getDataURL()->$result : Text
$result:="../../"+Localized string("149")+"/"
// -----------------------------
// MARK:Notes
// -----------------------------
Function getBDDnotesFolder($nomBDD : Text)->$result : Object
// nom du fichier .4DB = nom dossier sans le séparateur final
Case of
: (Not(Storage.System.estExécutéDansHôte))
// exécution en local ; utiliser une BDD de test
$result:=Folder(Structure file(*); fk platform path)
$result:=$result.parent.parent.parent.folder("Test MOB").folder($nomBDD+".4dbase")
$result:=$result.file($nomBDD)
: (Storage.System.typeApplication=ALV Client APP)
: (Storage.System.typeApplication=ALV BDD mère)
// bof
$result:=Folder(Structure file(*); fk platform path)
$result:=$result.parent.parent.parent.folder("Composants").folder("Matrices").folder("Test MOB").folder($nomBDD+".4dbase")
$result:=$result.file($nomBDD)
Else
// serveur ALV
$result:=This.getAppWorkSpaceFolder().folder(Localized string("112")).folder($nomBDD+".4dbase")
$result.create()
$result:=$result.file($nomBDD)
End case
⇧
[class]$session - 03/12/2025 12:10:03
property trace : cs._Trace
singleton Class constructor()
var parameters : Object
This.trace:=cs._Trace.me
// -----------------------------
// MARK:Validation
// -----------------------------
Function WEBmobileEmailChecker($request : Object)->$result : Object
var $session : Object
$result:=New object
//initialize shared variables
This._InitSession()
//check if the parameter file exists
If (parameters.success)
//get user session
$session:=Storage.pendingSessions[$request.session.id]
//check if the session exists
If ($session#Null)
//compare the current timestamp with that when creating the session
If ((Milliseconds-$session.time)<=parameters.timeout)
//if the difference is less than the value of the settings file: message to wait before sending an email again
$result.statusText:=parameters.message.waitSendMailConfirmationMessage
$result.success:=False
Else
//the timeout value is exceeded and send a new email
This.SendEmail($request; $result)
End if
Else
//send a confirmation email the 1st time
This.SendEmail($request; $result)
End if
// put the session on pending
$result.verify:=True
Else
$result.success:=False
$result.statusText:="Authentication failed, please contact the administrator for further assistance"
$result.errors:=New collection("Configuration to send validation email is not available"; parameters.statusText)
End if
Function SendEmail($request : Object; $response : Object)
var $htmlContent; $value; $stringError : Text
var $status; $template; $o; $transporter; $result; $session : Object
var $minutes : Integer
$stringError:=""
//get the path to the html email confirmation template
$template:=Folder(fk resources folder).folder("WEB mobile Server").file(parameters.template.emailToSend)
//check if the file exists
If (Asserted($template.exists; "Missing file "+$template.platformPath))
//method to send email
$o:=New object
$o.smtp:=New object
$o.smtp.host:=parameters.smtp.host
$o.smtp.acceptUnsecureConnection:=False
$o.smtp.port:=Choose($o.smtp.acceptUnsecureConnection; 465; 587)
$o.smtp.user:=parameters.smtp.user
$o.smtp.password:=parameters.smtp.password
$o.smtp.keepAlive:=True
$o.smtp.connectionTimeOut:=30
$o.smtp.sendTimeOut:=100
$o.mail:=New object
$o.mail.from:=parameters.smtp.from //get "from" value from settings file
$o.mail.to:=$request.email //get "email" value from settings file
$o.mail.subject:=parameters.emailSubject //get "emailSubject" value from settings file
$htmlContent:=$template.getText()
//create server address for session activation
//scheme: http or https
// hostname: 172.0.0.1
// port: 80
// path: activation
// session.id: ID de la session
// otherParameters: More parameters
$value:=parameters.activation.scheme+"://"+parameters.activation.hostname+":"+parameters.activation.port+"/"+parameters.activation.path+"?token="+$request.session.id+"?"+parameters.activation.otherParameters
$htmlContent:=Replace string($htmlContent; "{{url}}"; $value)
//convert milliseconde to Minute
$minutes:=(parameters.timeout/60000)
//display the timeout value in the email
$htmlContent:=Replace string($htmlContent; "{{expirationminutes}}"; String($minutes))
$o.mail.htmlBody:=$htmlContent
$transporter:=SMTP New transporter($o.smtp)
$status:=$transporter.send($o.mail)
//check if the email is sent
If ($status.success)
//get user session
$session:=Storage.pendingSessions[$request.session.id]
Use (Storage.pendingSessions)
If ($session#Null)
//update the timestamp if we send a new email after the expiration of the 1st connection
$session.time:=Milliseconds
Else
//add new session
Storage.pendingSessions[$request.session.id]:=New shared object(\
"team"; String($request.team.id); \
"application"; $request.application.id; \
"time"; Milliseconds)
End if
End use
End if
$result:=New object("status"; $status.success; "statusText"; $status.statusText; "error"; $stringError)
Else
$result:=New object("status"; False; "statusText"; $template.platformPath+" is not found"; "error"; $stringError)
End if
If ($result.status)
$response.statusText:=parameters.message.successConfirmationMailMessage
Else
$response.statusText:=$result.statusText
End if
$response.emailInfo:=$result
$response.success:=$result.status
// -----------------------------
// MARK:Activation
// -----------------------------
Function WebMobileActiveSession($url : Text)->$result : Object
This._InitSession()
//check if the parameter file exists
If (parameters.success)
If (Position(parameters.activation.path; $url)=2)
$result:=This.ActivateSessions($url)
End if
Else
WEB SEND TEXT("Please contact administrator to unlock your session")
$result:=New object
$result.success:=False
$result.errors:=New collection("Configuration to active session is not available"; parameters.statusText)
End if
Function ActivateSessions($url : Text)->$result : Object
var $template : 4D.File
var $sessionObjet; $session : Object
var $bodyMessage; $htmlContent; $token : Text
//get the path to the html email activation template
$template:=Folder(fk resources folder).folder("WEB mobile Server").file(parameters.template.emailConfirmActivation)
//return the information in to the database method
$result:=New object("success"; False; "message"; ""; "error"; "")
//check if the file exists
If ($template.exists)
//get token value from the url
$token:=This.getTokenFromURL($url)
//get user session
$session:=Storage.pendingSessions[$token]
//check if the session exists
If ($session#Null)
//compare the current timestamp with that when creating the session
If ((Milliseconds-$session.time)<parameters.timeout)
//if the difference is less than the value of the settings file: active the session
// get the session file
$sessionObjet:=This.getSessionObjet($token)
If ($sessionObjet#Null)
//update status value
$sessionObjet.status:="accepted"
Use (Storage.pendingSessions)
//delete session
OB REMOVE(Storage.pendingSessions; $token)
End use
$bodyMessage:=parameters.message.successActiveSessionsMessage
$result.success:=True
End if
Else
$bodyMessage:=parameters.message.expireActiveSessionsMessage
End if
Else
$bodyMessage:=parameters.message.expireActiveSessionsMessage
End if
Else
$result.error:="Missing file "+$template.platformPath
End if
$result.message:=$bodyMessage
//write the value of $bodyMessage in the web page
$htmlContent:=$template.getText()
$htmlContent:=Replace string($htmlContent; "{{message}}"; $bodyMessage)
WEB SEND TEXT($htmlContent)
// -----------------------------
// MARK:Mobile session
// -----------------------------
Function InitialiserSessionInfos($infos : Object)
var $data : Object
var $result : Boolean
This.InitialiserSession()
// enregistrer les infos dans la session
sharedObject($infos; Session.storage.mobileWebInfo)
sharedObject($infos.userInfo; Session.storage.userInfo)
// fixer les privilèges (on n'est plus Guest)
$data:=New object
$data.userName:=Session.storage.userInfo.userName
// ne PAS utiliser les roles (pb dans fichier .json
$data.privileges:=New collection("ReadRecords") // tout le monde pareil, sinon lire les userInfo (attribut de UtilisateursALV)
$result:=Session.setPrivileges($data)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Privilèves fixés "+Choose($result; "[OK]"; "[KO]"); Current method name; "Session id "+Session.id+" - idleTimeout "+String(Session.idleTimeout)+" mn - expirationDate "+String(Session.expirationDate)+" (voir détails dans logs)")
This.trace.EnvoyerMessages([msgk_log]; "Privilèves fixés "+Choose($result; "[OK]"; "[KO]"); Current method name; "$infos : "+JSON Stringify($infos))
This.trace.EnvoyerMessages([msgk_log]; "Privilèves fixés "+Choose($result; "[OK]"; "[KO]"); Current method name; "Session.storage.userInfo : "+JSON Stringify(Session.storage.userInfo))
// initialiser les variables session
This.InitUserData()
Function setSessionFile($nomFichier : Text; $request : Object; $userInfo : Object)
var $template; $texte : Text
$template:=Folder(fk resources folder).folder("TemplatesMobileWeb").file("mobileWeb.json").getText()
PROCESS 4D TAGS($template; $texte; $request; $userInfo)
cs._document.new().getMobileWebFolder().file($nomFichier).setText($texte)
Function getSessionObjet($nomFichier : Text)->$result : Object
// renvoie le contenu du fichier $nomFichier situé dans le dossier des sessions mobileWEB
var $fichier : 4D.File
var $sessions : Collection
$result:=Null
// lister toutes les sessions disponibles
$sessions:=cs._document.new().getMobileWebFolder().files(fk ignore invisible)
For each ($fichier; $sessions) While ($result=Null)
// chercher notre session
If ($fichier.name=$nomFichier)
// trouvé
$result:=JSON Parse($fichier.getText(); Is object)
End if
End for each
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Session demandée "+Choose($result=Null; "[KO]"; "[OK]"); Current method name; $nomFichier+", (info : session.id = "+Session.id+" -"+String($sessions.length)+" sessions enregistrées), (voir session dans logs)")
This.trace.EnvoyerMessages([msgk_log]; "Session demandée "+Choose($result=Null; "[KO]"; "[OK]"); Current method name; JSON Stringify($result))
Function getSessionDeCookie($data : Object)->$result : Boolean
// renvoie vrai si le cookie contient un ID de session active
var $token : Text
var $session : Object
$result:=False
// lire l'id de session dans le cookie
// il existe si la session a été créée par une activationByEmail
$token:=cs.$cookie.new().getMobileWebID()
If ($token#"")
// il existe
// lire le fichier session correspondant
$session:=This.getSessionObjet($token)
$result:=($session#Null)
If ($result)
// il existe, cas normal (par exemple, pas de ré initialisation du serveur...)
// renvoyer les infos de la session
$data.infos:=$session
End if
End if
Function InitialiserSession()
If (Not(OB Is defined(Session.storage; "userInfo")))
Use (Session.storage)
Session.storage.userInfo:=New shared object
End use
End if
If (Not(OB Is defined(Session.storage; "mobileWebInfo")))
Use (Session.storage)
Session.storage.mobileWebInfo:=New shared object
End use
End if
// -----------------------------
// MARK:User Data
// -----------------------------
Function InitUserData()
var $data : Object
// initialiser les variables session
This.InitUserParams()
This.InitHTTPvars()
// créer le dossier des fichiers temporaires de la session
$data:=cs._document.new().getSessionFolder()
$data.create()
Function InitUserParams()
// données de session
// utilisées au gré de la navigation de l'utilisateur
Use (Session.storage)
Session.storage.UserParams:=New shared object
End use
// initialiser les données de navigation
cs.$pageWebNAV.new().Initialiser()
Function InitHTTPvars()
var $data : Object
// .HTTPvars contient
// - des variables, de nom wwwXXX, utilisées dans les pages Web de recherche ou de saisie pour recupérer les données utilisateur
// RAPPEL : cette liste sert à initialiser TOUTES les variables process ; toutes ces variables doivent être dans cette liste
// - des variables autres, de nom YYY, utilisées dans les templates de page Web pour la construction des pages
Use (Session.storage)
Session.storage.HTTPvars:=New shared object
End use
$data:=Session.storage.HTTPvars
Use ($data)
// depuis v5.2 les 4DURL sont de la forme /4Dxxx/xxx/yyy
$data.wwwRacineRessources:="../../"
// fixer le contexte pour le composant CARTO
$data.wwwContexteWeb:="ServeurWeb"
End use
// -----------------------------
// MARK:Utilitaires
// -----------------------------
Function _InitSession()
//create a share collection accessible from several processes
If (Storage.pendingSessions=Null)
Use (Storage)
Storage.pendingSessions:=New shared object
End use
End if
//create an object accessible from the current process
If (parameters=Null)
parameters:=This.getSetting()
End if
Function getSetting()->$result : Object
var $settingFolder : 4D.Folder
var $template; $file : 4D.File
var $info : 4D.WebServer
$settingFolder:=Folder(fk resources folder).folder("WEB mobile Server")
$template:=$settingfolder.file("settings.json")
If ($template.exists)
$result:=JSON Parse($template.getText())
If ($result.activation=Null)
$result.activation:=New object
End if
$info:=WEB Server(Web server database)
If ($result.activation.scheme=Null)
$result.activation.scheme:=Choose($info.security.HTTPSEnabled; "https"; "http")
End if
If ($result.activation.hostname=Null)
$result.activation.hostname:=$info.options.webIPAddressToListen[0]
End if
If ($result.activation.port=Null)
$result.activation.port:=String(Choose($info.security.HTTPSEnabled; $info.options.webHTTPSPortID; $info.options.webPortID))
End if
If ($result.activation.path=Null)
$result.activation.path:="activation"
End if
If ($result.activation.otherParameters=Null)
$result.activation.otherParameters:=""
End if
If ($result.emailSubject=Null)
$result.emailSubject:="Application Name: Sign in confirmation"
End if
If ($result.timeout=Null)
$result.timeout:=300000
End if
If ($result.message=Null)
$result.message:=New object
End if
If ($result.message.successConfirmationMailMessage=Null)
$result.message.successConfirmationMailMessage:="Verify your email address"
End if
If ($result.message.waitSendMailConfirmationMessage=Null)
$result.message.waitSendMailConfirmationMessage:="The mail is already sent thank you to wait before sending again"
End if
If ($result.message.successActiveSessionsMessage=Null)
$result.message.successActiveSessionsMessage:="You are successfully authenticated"
End if
If ($result.message.expireActiveSessionsMessage=Null)
$result.message.expireActiveSessionsMessage:="This email confirmation link has expired!"
End if
If ($result.template=Null)
$result.template:=New object
End if
If ($result.template.emailToSend=Null)
$result.template.emailToSend:="ConfirmMailTemplate.html"
End if
$file:=$settingFolder.file($result.template.emailToSend)
If (Not($file.exists))
Folder(fk resources folder).folder("TemplatesMobileWeb").file("ConfirmMailTemplate.html").copyTo($settingFolder)
End if
If ($result.template.emailConfirmActivation=Null)
$result.template.emailConfirmActivation:="ActiveSessionTemplate.html"
End if
$file:=$settingFolder.file($result.template.emailConfirmActivation)
If (Not($file.exists))
Folder(fk resources folder).folder("TemplatesMobileWeb").file("ActiveSessionTemplate.html").copyTo($settingFolder)
End if
$result.success:=True
Else
$result:=New object("success"; False; "statusText"; "Missing configuration files "+$template.platformPath)
If (Not($settingFolder.exists))
$settingFolder.create()
End if
$file:=$settingFolder.file("settings.sample.json")
If (Not($file.exists))
Folder(fk resources folder).folder("TemplatesMobileWeb").file("settings.sample.json").copyTo($settingFolder)
End if
End if
Function getTokenFromURL($url : Text)->$result : Text
var $texte : Text
$texte:=Split string($url; "?")[1]
$result:=Substring($texte; Position("="; $texte)+1)
Function getTokenFromSession()->$result : Text
$result:=""
Case of
: (Not(OB Is defined(Session.storage; "mobileWebInfo")))
: (Not(OB Is defined(Session.storage.mobileWebInfo; "session")))
: (Not(OB Is defined(Session.storage.mobileWebInfo.session; "id")))
Else
$result:=Session.storage.mobileWebInfo.session.id
End case
⇧
[class]$pageWebLOGIN - 01/03/2026 13:19:27
property check : cs.$authentificationEmail
property sessionUser; Utilisateur : cs.UtilisateursALV
Class extends $pageWeb
Class constructor()
Super()
This.check:=cs.$authentificationEmail.new()
//----------------------------------
// MARK:Traitement url
//----------------------------------
Function seConnecter()
// tout commence ici
TEXT TO DOCUMENT(cs.xSDK.Traces.new().GetGarbageDossier().folder("_WEBMOdebug/"+Current method name).file(Timestamp+"1.json").platformPath; "mobileWebInfo est null : "+String(Session.storage.mobileWebInfo=Null))
TEXT TO DOCUMENT(cs.xSDK.Traces.new().GetGarbageDossier().folder("_WEBMOdebug/"+Current method name).file(Timestamp+"2.json").platformPath; "mobileWebInfo est null : "+String(Session.storage.mobileWebInfo=Null)+Char(CR ASCII code)+JSON Stringify(cs.$cookie.me.Lire(); *))
Case of
: (This.ReConnexion())
// on envoyé une page Web
: (Not(This.ValiderDevice()))
// erreur traitée
: (This.paramsUrl.length=0)
// se connecter depuis l'extérieur
// envoyer la page de connexion
This.Envoyer("LoginByEmail.shtml"; "accueil")
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Connexion"; Current method name; "Pas de paramètre de connexion ; la page 'LoginByEmail' a été envoyée")
: (This.Authentifier(This.paramsUrl[0]).waiting)
// une demande de confirmation d'authentication a été envoyée ; on attend la réponse
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Connexion"; Current method name; "Une adresse eMail a été traitée ; on attend la confirmation")
: (This.Authentifier(This.paramsUrl[0]).success)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Connexion"; Current method name; "L'eMail a été traité ; la page a dû être envoyée")
Else
// oups !
This.Envoyer("LoginByEmail.shtml"; "accueil")
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Connexion"; Current method name; "Erreur ; adresse eMail non traitée, session mobileWeb non créée")
End case
Function Settings()
This.Envoyer("Settings.shtml"; "accueil")
//----------------------------------
// MARK:Element HTML
//----------------------------------
Function EcrireUserAuthentification()
var $texte; $ElémentXML; $adresseEmail : Text
This.getUser()
This.InitStructureXML("article"; "saisieEmail")
// email saisi
$texte:="EmailSaisi"
$ElémentXML:=DOM Create XML element(This.RacineXML; "p"; "class"; "elementLibelleSaisieEmail")
$ElémentXML:=DOM Create XML element(This.RacineXML; "p/label"; "for"; $texte)
DOM SET XML ELEMENT VALUE($ElémentXML; "EMAIL")
$adresseEmail:=Choose(OB Is defined(Session.storage; "mobileWebInfo"); Session.storage.mobileWebInfo.email; "")
$ElémentXML:=DOM Create XML element(This.RacineXML; "input"; "class"; "elementSaisieEmail"; "value"; $adresseEmail; "type"; "email"; "id"; $texte; "name"; $texte; "pattern"; "+@example\\.com"; "size"; "30"; "required"; "")
$texte:=This.ExporterStructureXML()
This.result.resultat:=Char(1)+$texte
Function getUser()
This.sessionUser:=cs.UtilisateursALV.new(Session.userName)
//----------------------------------
// MARK:LOGIN par eMail
//----------------------------------
Function Authentifier($paramsUrl : Text)->$result : Object
var $request; $response; $data : Object
If (Session.storage.mobileWebInfo#Null)
// le processus d'authentication est terminé, fixer les privilèges (on n'est plus Guest)
Use (Session.storage.UserParams)
Session.storage.UserParams.EtatNavigation:="Personnes"
End use
// fixer les privilèges
$data:=New object
$data.userName:=Session.storage.userInfo.userName
// ne PAS utiliser les roles (pb dans fichier .json
$data.privileges:=New collection("ReadRecords") // tout le monde pareil, sinon lire les userInfo (attribut de UtilisateursALV)
Session.setPrivileges($data)
$response:=New object
$response.waiting:=False
$response.success:=True
WEB SEND TEXT(JSON Stringify($response))
Else
// récupérer l'adresse email saisi
$request:=JSON Parse($paramsUrl)
// versionner
This.getAppInfo($request)
// renseigner le context
This.getWebBrowserInfo($request)
// vérifier si l'adresse eMail est un identifiant connu et envoyer l'eMail
$response:=This.check.Authentification($request)
$response.message:=$response.statusText
$response.waiting:=True & ($response.success)
// si OK un eMail a été envoyé
// ici on envoie .waiting= true et .succcess function d'état du processus
WEB SEND TEXT(JSON Stringify($response))
End if
$result:=$response
Function ValiderDevice()->$result : Boolean
var $template : 4D.File
var $htmlContent : Text
$result:=This.isValidDevice()
If (Not($result))
$template:=Folder(fk resources folder).folder("TemplatesMobileWeb").file("ErreurServeur.html")
$htmlContent:=$template.getText()
$htmlContent:=Replace string($htmlContent; "{{message}}"; Localized string("1022"))
WEB SEND TEXT($htmlContent)
End if
Function getAppInfo($requete : Object)
var $data : Object
$data:=cs.xSDK.$composant.new()
$data.LireInfoPlist(Folder(fk resources folder).file("Info.plist"))
$requete.application:=New object
$requete.application.name:=$data.infoPlist.query("key = :1"; "CFBundleName")[0].string
$requete.application.id:="ALV 16800"
$requete.application.version:=$data.infoPlist.query("key = :1"; "CFBundleVersion")[0].string
⇧
[class]_composant - 12/03/2026 12:39:48
property environnement : cs.xSDK.EnvironnementALV
property document : cs._document
property trace : cs._Trace
property rsc : cs.xSDK.ResourceALV
property cFct : cs._CommunFunctions
// propriétés des appelants
property RacineXML : Text
Class constructor()
// environnement
This.environnement:=cs.xSDK.EnvironnementALV.new()
This.document:=cs._document.new()
This.trace:=cs._Trace.me
This.rsc:=cs.xSDK.ResourceALV.me
This.cFct:=cs._CommunFunctions.me
//---------------------
// MARK: Installation
//---------------------
Function InitVariablesWEB()
var $data : Object
Use (Storage)
Storage["System"]:=New shared object
Storage["Host"]:=New shared object
Storage["Application"]:=New shared object
Storage["Processes"]:=New shared object
Storage["BDD"]:=New shared object
Storage["ServeurHTTP"]:=New shared object
End use
Use (Storage.System)
// sert, en particulier, pour les process de type monitoring
Storage.System.ArrêtAPP:=False
Storage.System.estExécutéDansHôte:=False
Storage.System.estExécutéDansAPP:=False
// tout le monde n'est pas initialisé ; on ne sait pas si on est serveur Web
Storage.System.estServeurWeb:=False
Storage.System.typeApplication:=This.environnement.typeApplication()
Storage.System.estServeur:=This.environnement.estServeur()
Storage.System.estClient:=This.environnement.estClient()
End use
Use (Storage.Host)
Storage.Host.Session_Etat:=0
End use
// pour la navigation
Use (Storage.BDD)
Storage.BDD.navAll:=New shared object
End use
Use (Storage.ServeurHTTP)
// fixer le nom du serveur Web
Storage.ServeurHTTP.nom:=File(Structure file; fk platform path).name
End use
// rappel : les constantes sont partagées (=> définies dans SDK)
// partager des ressources
$data:=New object
// fichier de ressources
$data.chemin:=Get 4D folder(Current resources folder)+"DataServeur.xml"
This.rsc.Inscrire(Est Ressource WEBMO; $data)
Function Installer()
// installer les ressources du composant
Partager Ressources("Installer Ressources Composant"; New object("dossier"; Get 4D folder(Current resources folder); "IDnom"; "MobWEB"))
This.InstallerDonnéesHote()
This.IntegerDansHote()
cs._maintenance.new().ChargerBDDmobile()
Case of
: (Storage.System.estServeur)
// on est sur un serveur HTTP
This.InstallerServeur()
// lancer le serveur Web
cs.$serveur.new().Demarrer()
// lancer la maintenance
cs._maintenance.new().Démarrer()
Else
// BDDmère ou APP ou client
End case
Function InstallerDonnéesHote()
// lire les données d'installation
var $data : Object
var $attribut : Text
Case of
: (Not(Storage.System.estExécutéDansHôte))
: (Storage.System.typeApplication=ALV Client APP)
: (Storage.System.typeApplication=4D Remote mode)
// filtrer
Else
$data:=New object
EXECUTE METHOD(Lire Données Hôte Partagées; $data)
// recopier les données reçues
Use (Storage.Host)
For each ($attribut; OB Keys($data))
Storage.Host[$attribut]:=$data[$attribut]
End for each
End use
End case
// utile pour les réactiver en mode compilé
SET ASSERT ENABLED(Storage.Host.Session_Etat ?? 6)
Function InstallerServeur()
// placer les pages HTML et ressources du serveur dans le dossier du site
// rappel : ne concerne pas l'APP autonome (composant non présent)
var $dossierDestination : Object
// dossier d'installation
$DossierDestination:=This.document.getRacineHTMLFolder()
If ($dossierDestination=Null)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Démarrage"; Current method name; "InstallerSurServeur [KO], pas de serveur Web actif")
Else
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Démarrage"; Current method name; "InstallerSurServeur [OK] dans "+$dossierDestination.platformPath)
$dossierDestination.delete(Delete with contents)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Démarrage"; Current method name; "Vidage du dossier racine [OK] "+$dossierDestination.platformPath)
This.InstallerPagesDynamiques($dossierDestination)
This.InstallerRessources($dossierDestination)
This.InstallerRessourcesMEDIA($dossierDestination)
This.InstallerRessourcesCARTO($dossierDestination)
This.InstallerRessourcesSSL($dossierDestination)
// installer les ressources Web albums
cs.xALB.$albums.new().InstallerRessourcesSurServeur($dossierDestination)
End if
Function InstallerPagesDynamiques($dossierDestination : Object)
// Ajouter les pages dynamiques
Dupliquer ContenuDeDossier(Folder(Get 4D folder(Current resources folder); fk platform path).folder("TemplatesPagesWeb"); $dossierDestination)
Function InstallerRessources($dossierDestination : Object)
var $dossier : Object
$dossier:=$dossierDestination.folder("ressources")
$dossier.create()
// Ajouter les feuilles de style
COPY DOCUMENT(Folder(Get 4D folder(Current resources folder); fk platform path).folder("css").platformPath; $dossier.platformPath; *)
// Ajouter les ressources images
COPY DOCUMENT(Folder(Get 4D folder(Current resources folder); fk platform path).folder("Images").folder("HTML").platformPath; $dossier.platformPath; "images"; *)
// Ajouter les fichiers Java
COPY DOCUMENT(Folder(Get 4D folder(Current resources folder); fk platform path).folder("javascripts").platformPath; $dossier.platformPath; "js"; *)
Function InstallerRessourcesMEDIA($dossierDestination : Object)
var $dossierSource : 4D.Folder
$dossierSource:=This.document.getDataFolder()
$dossierSource.copyTo($dossierDestination; Localized string("149"); fk overwrite)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance Medias"; Current method name; "Dossier source "+$dossierSource.platformPath)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance Medias"; Current method name; "Dossier destination "+$dossierDestination.platformPath)
Function InstallerRessourcesCARTO($dossierDestination : Object)
If (Storage.System.estExécutéDansHôte)
// ressources OL-IGN
// mêmes ressources que la BDD mère
cs.xCarto.$carte.new().InstallerRessources($DossierDestination.platformPath)
End if
Function InstallerRessourcesSSL($dossierDestination : Object)
// recopier les certificats pour le serveur Web
var $DossierSource : Object
var $dataTexte : Text:=""
If (Storage.System.estExécutéDansHôte)
This.rsc.SetVariable(Est Ressource WEBMO; "Serveur_web/nomDossierSSL"; Is text; ->$dataTexte)
// rappel : $dataTexte dit quel est le certificat (certifié ou autosigné) à utiliser
// situé dans les ressources hote
$DossierSource:=Folder(Get 4D folder(Current resources folder; *); fk platform path)
$DossierSource:=$DossierSource.folder("SSL").folder($dataTexte)
// dans
$DossierDestination:=This.document.getCertificatSSLFolder()
// copier les certificats
COPY DOCUMENT($DossierSource.platformPath; $DossierDestination.parent.platformPath; $DossierDestination.name; *)
End if
Function IntegerDansHote()
// BDDmère ou APP ou client
// intégrer le composant dans la base hôte, pour les interfaces :
If (Storage.System.estExécutéDansHôte)
// dans cette version rien à faire
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Intégration"; Current method name; "Intégrer dans base hôte ; application ALV "+String(Storage.System.typeApplication))
End if
//----------------------------------
// MARK:Variables process session
//----------------------------------
//----------------------------------
//MARK:Variables contexte
//----------------------------------
Function InitContexte($url : Text)
var $vs4D : Text
$vs4D:="4D4D"
Case of
: ($url="@albums@")
$vs4D:="4D4Dalbum"
End case
If (Not(Session.isGuest()))
// cas du serveur Web avec un user connu
$vs4D:="4D4Dprivate"
End if
If (Not(OB Is defined(Session.storage; "HTTPvars")))
Use (Session.storage)
Session.storage.HTTPvars:=New shared object
End use
End if
// stocker
Use (Session.storage.HTTPvars)
Session.storage.HTTPvars.vs4D:=$vs4D
End use
//----------------------------------
// MARK:Utilitaires
//----------------------------------
Function InitResult($Error : Integer; $ErrorDescription : Text; $success : Boolean)->$result : Object
If (Count parameters=0)
$Error:=0
$ErrorDescription:=""
$success:=True
End if
$result:=New object("Error"; $Error; "ErrorDescription"; $ErrorDescription; "success"; $success)
$result.nomMethode:=Current method name
// ----------------------
//MARK:Utilitaires XML
// -----------------------
Function InitStructureXML($ref : Text; $nomClass : Text)
This.RacineXML:=DOM Create XML Ref($ref)
DOM SET XML ATTRIBUTE(This.RacineXML; "class"; $nomClass)
Function ExporterStructureXML()->$result : Text
var $datatexte : Text
DOM EXPORT TO VAR(This.RacineXML; $datatexte)
DOM CLOSE XML(This.RacineXML)
$result:=This.Nettoyer($datatexte)
Function Nettoyer($texte : Text)->$result : Text
// structure est le mot-clé pour renvoyer le corps du texte
$texte:=Substring($texte; Position("<"; $texte; 2; *))
If ($texte="@structure@")
$texte:=Substring($texte; Position("<"; $texte; 2; *))
$texte:=Substring($texte; 1; Position("</structure"; $texte)-1)
End if
$result:=Replace string($texte; "\r\r"; "")
⇧
[class]SitesSelect - 04/06/2026 14:24:49
Class extends _WEBMO_DataStore
Class constructor($requête : Variant)
Super("SitesSelect"; $requête)
This.selection:=Null
// ----------------------
//MARK:PageHTML
// ----------------------
Function CreerBDDmobile($tâche : cs.xSDK.Tache)->$result : Collection
var $entité : cs.Sites
// créer la sélection d'entités
This.Créer()
// créer les entités de la BDD mobile
$result:=New collection
If (This.selection.length>0)
// ordonner
This.selection:=This.selection.orderBy("nom asc")
For each ($entité; This.selection) While (Not($tâche.Tuer.signaled))
$result.push($entité.CreerBDDentity())
End for each
End if
⇧
[class]MediasSelect - 04/06/2026 14:26:14
property fct : cs.xSDK.Outils
Class extends _WEBMO_DataStore
Class constructor($requête : Variant)
Super("MediasSelect"; $requête)
This.fct:=cs.xSDK.Outils.me
This.selection:=Null
This.length:=0
// ----------------------
//MARK:PageHTML
// ----------------------
Function CreerBDDmobile($tâche : cs.xSDK.Tache)->$result : Collection
var $entité : cs.Medias
// créer la sélection d'entités
This.Créer()
// créer les entités de la BDD mobile
$result:=New collection
If (This.selection.length>0)
// ordonner
This.selection:=This.selection.orderBy("dateNum asc")
For each ($entité; This.selection) While (Not($tâche.Tuer.signaled))
$result.push($entité.CreerBDDentity())
End for each
End if
// -----------------------------
// MARK:Maintenance
// -----------------------------s
Function CréerMediaMobile($tâche : cs.xSDK.Tache)
// télécharger les media de la sélection et les mettre dans $dossier au format mobile
var $dossier : 4D.Folder
var $entité; $data; $result; $fichier; $application : Object
var $pict : Picture
var $gauche; $haut; $droite; $bas; $largeur; $hauteur : Integer
var $zoom : Real
$dossier:=This.document.getMediasFolder()
$application:=Storage.Host.$application.call()
For each ($entité; This.selection) While (Not($tâche.Tuer.signaled))
$fichier:=$dossier.file($entité.getMediaNom())
Case of
: ($fichier.exists)
// le media mobile existe déjà, pas besoin de recharger
Else
// ok on y va
$data:=New object("IDnomFichier"; String($entité.ID); "cheminDestination"; $dossier.platformPath; "Options"; 0)
// dans ce process ; avec -1 pas de mise à jour FORM
$result:=$application.TelechargerFichierMedia($data)
// le fichier est dans $resultat.fichier
If ($result.success)
// recadrer l'image ; taille image max 1200 (hauteur et largeur)
READ PICTURE FILE($result.fichier.platformPath; $pict)
// nettoyer
$result.fichier.delete()
PICTURE PROPERTIES($pict; $largeur; $hauteur)
$zoom:=-Scaled to fit prop centered
$gauche:=0
$haut:=0
$droite:=WebMob Image largeur
$bas:=WebMob Image hauteur
This.fct.CalculerRectangleMedia(->$gauche; ->$haut; ->$droite; ->$bas; $largeur; $hauteur; ->$zoom)
$pict:=$pict*$zoom
// passer en JPEG
CONVERT PICTURE($pict; WebMob Image format; 0.5)
WRITE PICTURE FILE($fichier.platformPath; $pict; WebMob Image format)
Waiting(1)
End if
End case
End for each
Function CréerMediaMobileNew($tâche : cs.xSDK.Tache)
// télécharger les media de la sélection et les mettre dans $dossier au format mobile
var $dossier : 4D.Folder
var $entité; $data; $result; $fichier; $application : Object
var $pict : Picture
var $gauche; $haut; $droite; $bas; $largeur; $hauteur : Integer
var $zoom : Real
$dossier:=This.document.getMediasFolder()
$application:=Storage.Host.$application.call()
For each ($entité; This.selection) While (Not($tâche.Tuer.signaled))
$fichier:=$dossier.file($entité.getMediaNom())
Case of
: ($fichier.exists)
// le media mobile existe déjà, pas besoin de recharger
Else
// ok on y va
$data:=New object("IDnomFichier"; String($entité.ID); "cheminDestination"; $dossier.platformPath; "Options"; 0)
// dans ce process ; avec -1 pas de mise à jour FORM
$result:=$application.TelechargerFichierMedia($data)
// le fichier est dans $resultat.fichier
Case of
: (Not($result.success))
: ($entité.type=1)
// recadrer l'image ; taille image max 1200 (hauteur et largeur)
READ PICTURE FILE($result.fichier.platformPath; $pict)
// nettoyer
$result.fichier.delete()
PICTURE PROPERTIES($pict; $largeur; $hauteur)
$zoom:=-Scaled to fit prop centered
$gauche:=0
$haut:=0
$droite:=WebMob Image largeur
$bas:=WebMob Image hauteur
This.fct.CalculerRectangleMedia(->$gauche; ->$haut; ->$droite; ->$bas; $largeur; $hauteur; ->$zoom)
$pict:=$pict*$zoom
// passer en JPEG
CONVERT PICTURE($pict; WebMob Image format; 0.5)
WRITE PICTURE FILE($fichier.platformPath; $pict; WebMob Image format)
: ($entité.type=2)
// pour l'instant recopie du PDF
$result.fichier.rename($fichier.name+".pdf")
End case
Waiting(1)
End case
End for each
//Function CompresserPDF($fichier : 4D.File)
//If (This.existsPlugIn())
//End if
//Function existsPlugIn()->$result : Boolean
//ARRAY LONGINT($tabNum; 0)
//ARRAY TEXT($Elements; 0)
//PLUGIN LIST($tabNum; $Elements)
//// ID "AinsiLaVie Pack" = 15003, défini dans "4D Plugin Wizard"
//If (Find in array($tabNum; 15003)=-1)
//$result:=False
//Else
//$result:=True
//End if
⇧
[class]$notes - 14/10/2025 14:46:21
property request; formats : Object
Class extends $pageWeb
Class constructor($request : Object)
Super()
This.request:=$request
This.formats:=New object
This.formats.Personnes:=New object("Options"; 0x0007)
This.formats.Communes:=New object("Options"; 0x00010000)
This.formats.Medias:=New object("Options"; 0x0000)
// -----------------------------
// MARK:Gestion de la BDD Notes
// -----------------------------
Function ListerTables($data : Object)->$result : Collection
// ici on est sur le serveur (ou la BDD mère en test)
// ouvrir la BDD notes
This.OuvrirBDD_externe()
// lister les noms de tables de la requete
ARRAY LONGINT($tabID; 0)
ARRAY TEXT($tabNomTable; 0)
Begin SQL
SELECT id, nomTable FROM notes INTO :$tabID, :$tabNomTable;
End SQL
// passer en collection
$result:=New collection
If (Size of array($tabID)>0)
ARRAY TO COLLECTION($result; $tabID; "ID"; $tabNomTable; "nomTable")
End if
// fermer
This.FermerBDD_externe()
Function LireBDD($data : Object)->$result : Collection
// ici on est sur le serveur (ou la BDD mère en test)
var $nomTable : Text
// ouvrir la BDD notes
This.OuvrirBDD_externe()
// lister les notes de la requete
$nomTable:=$data.DataClassNom
ARRAY LONGINT($tabID; 0)
ARRAY TEXT($tabUser; 0)
ARRAY TEXT($tabDate; 0)
ARRAY TEXT($tabNomTable; 0)
ARRAY TEXT($tabIDunique; 0)
ARRAY TEXT($tabObjet; 0)
ARRAY TEXT($tabContenu; 0)
Begin SQL
SELECT id, auteur, noteDate, nomTable, IDunique, objet, contenu FROM notes WHERE nomTable = :$nomTable INTO :$tabID, :$tabUser, :$tabDate, :$tabNomTable, :$tabIDunique, :$tabObjet, :$tabContenu;
End SQL
// passer en collection
$result:=New collection
If (Size of array($tabID)>0)
ARRAY TO COLLECTION($result; $tabID; "ID"; $tabUser; "auteur"; $tabDate; "noteDate"; $tabNomTable; "nomTable"; $tabIDunique; "IDunique"; $tabObjet; "objet"; $tabContenu; "contenu")
End if
// fermer
This.FermerBDD_externe()
Function SupprimerDansBDD($params : Object)
var $ID : Integer
Case of
: (Not(OB Is defined($params; "sélection")))
: (Not(Value type($params.sélection)=Is collection))
: ($params.sélection.length=0)
Else
// on a tout
// ouvrir la BDD notes
This.OuvrirBDD_externe()
Begin SQL
START TRANSACTION;
End SQL
For each ($ID; $params.sélection)
Begin SQL
DELETE FROM notes WHERE ID = :$ID;
End SQL
End for each
Begin SQL
COMMIT TRANSACTION;
End SQL
// fermer
This.FermerBDD_externe()
End case
Function OuvrirBDD_externe()
// Ouvrir (ou créer si elle n'existe pas) une BDD externe, via SQL
var $sql_BDDpath; $sql_BDDcourantePath; $texte : Text
var $table; $champ : Object
var $c : Collection
Case of
: (Storage.System.typeApplication=ALV Client APP)
: (Storage.System.typeApplication=4D Remote mode)
// filtrer
Else
// fixer le nom de la BDD externe ouvrir
$sql_BDDpath:=This.document.getBDDnotesFolder("BDD_NOTES").platformPath
// lire la BDD externe ouverte
$sql_BDDcourantePath:=""
Begin SQL
SELECT DATABASE_PATH() FROM _USER_SCHEMAS LIMIT 1 INTO :$sql_BDDcourantePath;
End SQL
If (Position("/"; $sql_BDDcourantePath)>0)
$sql_BDDcourantePath:=Convert path POSIX to system($sql_BDDcourantePath)
End if
// rappel : ouverture de la BDD en auto_close de sorte qu'elle puisse être ouverte par plusieurs applications (ex le serveur par AppMobile ou la BDD mère)
Case of
: ($sql_BDDpath+".4DB"=$sql_BDDcourantePath)
// déjà ouverte, ne rien faire
: (Test path name($sql_BDDpath+".4DB")=Is a document)
// ouverture d'une BDD existante
Begin SQL
USE DATABASE DATAFILE :$sql_BDDpath AUTO_CLOSE;
End SQL
// attention ici on est thread-safe
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Initialisation"; Current method name; "Ouverture de '"+$sql_BDDpath+"'")
Else
Waiting(30)
// nouvelle BDD externe
//-- créer les fichiers $fichier.4DB et $fichier.4DD
//-- créer / mettre à jour la structure
//-- créer les index
//-- envoyer les requêtes SQL vers la BDD externe
// lire les données de création de la structure BDD
$texte:=Document to text(Folder(Get 4D folder(Current resources folder); fk platform path).folder("Enumérations").file("Structure_BDD_Notes.json").platformPath)
$c:=JSON Parse($texte; Is collection)
Begin SQL
CREATE DATABASE IF NOT EXISTS DATAFILE :$sql_BDDpath;
USE DATABASE DATAFILE :$sql_BDDpath AUTO_CLOSE;
End SQL
For each ($table; $c)
// on a une table
Case of
: (Not(OB Is defined($table; "nomTable")))
: (Not(OB Is defined($table; "champs")))
: ($table.champs.length=0)
Else
// ok on a une table et ses champs
$texte:="CREATE TABLE IF NOT EXISTS "+$table.nomTable
// lister les champs
$texte:=$texte+" ("
For each ($champ; $table.champs)
$texte:=$texte+$champ.champ+" "+$champ.type+", "
End for each
// fermer
$texte:=Substring($texte; 1; Length($texte)-2)+");"
End case
Begin SQL
EXECUTE IMMEDIATE :$texte;
End SQL
// id automatique
$texte:="ALTER TABLE "+$table.nomTable+" MODIFY id ENABLE AUTO_INCREMENT;"
Begin SQL
EXECUTE IMMEDIATE :$texte;
End SQL
End for each
This.trace.EnvoyerMessages([msgk_event]; "Process "+Current process name; Current method name; "Création de '"+$sql_BDDpath+"'")
End case
// Maintenant toutes les requêtes SQL du process sont dirigées vers $sql_BDDpath
End case
Function FermerBDD_externe()
// retour à la BDD mère
Begin SQL
USE DATABASE SQL_INTERNAL;
End SQL
// -----------------------------
// MARK:Traitement des actions
// -----------------------------
Function Traiter($response : Object)->$result : Boolean
$result:=False
Case of
: (This.request.action="")
: (Not(OB Is defined(This; This.request.action)))
// action est autre chose qu'une function de this ; laisser passer
Else
$result:=True
// exécuter l'url
This[This.request.action]($response)
End case
Function AjouterNote($response : Object)
// enregistrer This.request.EntitéRéduite
This.EcrireNote()
// demander la mise à jour FORM
$response.dataSynchro:=True
$response.statusTexte:=Localized string("13")
Function EcrireNote()
// enregistrer la note de This.request
var $nomTable; $IDunique; $noteDate; $auteur; $objet; $contenu : Text
// ici on a une entité réduite
$nomTable:=This.request.EntitéRéduite.DataClassNom
$IDunique:=This.request.EntitéRéduite.IDunique
$noteDate:=String(Current date; ISO date GMT; Current time)
$objet:=This.request.note.objet
$contenu:=This.request.note.contenu
$auteur:=Localized string("14")
Case of
: (Session=Null)
: (Session.userName="")
Else
$auteur:=Session.userName
End case
// ouvrir la BDD notes
This.OuvrirBDD_externe()
// enregistrer et fermer
Begin SQL
START TRANSACTION;
INSERT INTO notes (nomTable, IDunique, noteDate, auteur, objet, contenu) VALUES ( :$nomTable, :$IDunique, :$noteDate, :$auteur, :$objet, :$contenu);
COMMIT TRANSACTION;
USE LOCAL DATABASE SQL_INTERNAL;
End SQL
This.FermerBDD_externe()
// ici pas de retour
// -----------------------------
// MARK:Traitement des URL
// -----------------------------
Function LireNotes($data : Object)->$result : Boolean
// lire toutes les notes de la table .DataClassNom
var $auteur; $libellé : Text
var $c; $c1; $c2 : Collection
var $note : Object
// lire la BDD notes
$c:=This.LireBDD($data)
$result:=($c.length>0)
If ($c.length>0)
// collection des user ayant créé une note pour $data
$c1:=$c.extract("auteur").distinct()
If ($c1.length>0)
$data.notes:=""
For each ($auteur; $c1)
// lire les notes de $auteur
$c2:=$c.query("auteur = :1"; $auteur).orderBy("noteDate asc")
// les lire
If ($c2.length>0)
$data.notes:=$data.notes+"<h2>Par "+$auteur+"</h2>"
For each ($note; $c2)
$libellé:=This.Libellé($data.DataClassNom; $note.IDunique)
$data.notes:=$data.notes+"<p>"+$libellé+" - "+$note.objet+" : "+$note.contenu+" (le "+String(Date($note.noteDate); System date abbreviated)+" à "+String(Time($note.noteDate); System time short)+")"+"</p></br>"
End for each
End if
End for each
Else
$data.notes:="<h2>"+Localized string("1101")+"</h2>"
End if
Else
// BDD vide
$data.notes:="<h2>"+Localized string("1101")+"</h2>"
End if
Function Libellé($DataClassNom : Text; $IDunique : Text)->$result : Text
var $entité : Object
If ($DataClassNom="ALB_@")
// un media d'album
$result:=Session.storage.ALB_UserParams.Album.Medias.query("MED_IDunique = :1"; $IDunique)[0].MED_Nom
$result:=$result+" (ID "+$IDunique+")"
Else
$entité:=cs.xSQL[$DataClassNom].new($IDunique)
If ($entité=Null)
$result:=""
Else
// entité de la BDD mère (ID existe)
$result:=" (ID "+String($entité.ID)+")"
End if
End if
⇧
[class]Lieux - 04/10/2025 09:34:46
property nom; label; commentaire : Text
property type : Integer
property lesEvenements : Object
Class extends _WEBMO_DataStore
Class constructor($IDentité : Variant)
// initialiser l'objet avec les données de l'entité $IDentité de la BDD
Super("Lieux"; $IDentité)
// ----------------------
//MARK:Sélection
// ----------------------
Function _LesEvents()
// créer la collection des events
var $selection : cs.EventsSelect
$selection:=cs.EventsSelect.new(This.dataClass.LesEvents())
$selection.Créer()
Use (This)
This.lesEvenements:=New shared object
End use
This.cFct.AjouterObjetA($selection; This; "lesEvenements")
// ----------------------
//MARK: FORM Liste
// ----------------------
Function NombreEvents()->$result : Text
This._LesEvents()
$result:=""
$result+=This.AddEventsType(22000; 1220)
$result+=This.AddEventsType(22300; 1223)
$result+=This.AddEventsType(33600; 1236)
$result+=This.AddEventsType(33700; 1237)
$result+=This.AddEventsType(33800; 1238)
$result+=This.AddEventsType(22100; 1221)
$result+=This.AddEventsType(22200; 1222)
If ($result="")
$result:=Localized string("1073")
End if
Function AddEventsType($type : Integer; $typeLabel : Integer)->$result : Text
var $c : Collection
var $sélection : cs.EventsSelect
$result:=""
$c:=This.lesEvenements.selection.query("type >= :1 and type <= :2"; $type; $type+99)
If ($c.length>0)
// créer une sous selection d'events
$sélection:=cs.EventsSelect.new()
$sélection.selection:=$c
$result:="<p>"+String($sélection.selection.length)+" "+Lowercase(This.cFct.LireLocatedSTR($typeLabel; New object("genre"; False; "plur"; ($sélection.selection.length>1))); *)+" :</p>"
$result+="<p>"+$sélection.LesMembres()+"</p></br>"
End if
Function get labeledNom()->$result : Text
$result:=This.nom+" ("+This.label+")"
Function get label()->$result : Text
$result:=This.cFct.LireLocatedSTR(This.type)
// ----------------------
//MARK: FORM Detail
// ----------------------
Function EtatCivil()->$result : Text
var $c : Collection
var $type : Integer
var $selection : cs.EventsSelect
$result:=""
// lister tous les types d'events de ce lieu
This._LesEvents()
$c:=This.lesEvenements.selection.extract("type").distinct().orderBy(ck ascending)
// pour chaque type, lister les events
If ($c.length>0)
For each ($type; $c)
$result+=This.cFct.LireLocatedSTR($type)+", "+Localized string(String(16000000+$type))+Char(Line feed)
$selection:=cs.EventsSelect.new()
$selection.selection:=This.lesEvenements.selection.query("type = :1"; $type).orderBy("dateNum asc")
$result+=$selection.EtatCivil()
End for each
End if
⇧
[class]_WEBMO_DataStore - 30/10/2025 12:58:49
property cFct : cs._CommunFunctions
property dataClass : Object
property selection; collection : Collection
property length : Integer
property _tagUrl : Text:="/4DCGI/"
// attributs de classe
property DataClassNom : Text
property numTable : Integer
property ID : Integer
property IDunique : Text
property ChampsExposés : Collection
Class extends _composant
Class constructor($DataClassNom : Text; $data : Variant)
Super()
This.cFct:=cs._CommunFunctions.me
This.dataClass:=cs.xSQL[$DataClassNom].new($data)
// récupérer les attributs scalaires dans this : .DataClassNom, .collection et .length
cs.xSDK.Outils.me.CopierAttributs(This.dataClass; This)
Function CreerBDDentity($data : Object; $c : Collection)
var $attribut : Text
For each ($attribut; $c)
$data[$attribut]:=This[$attribut]()
End for each
Function labelDataClass($prefix : Text)->$result : Text
$result:=$prefix+This.DataClassNom
// supprimer le s final
$result:=Substring($result; 1; Length($result)-1)
$result:=Uppercase($result)
Function Titrer()->$result : Text
$result:=This.cFct.LireLocatedSTR(This.numTable)
Function InformationEntité($data : Object)->$result : Text
// créer le texte de l'entité $params; utilise un template
var $event : cs.Events
var $lesUnions : cs.UnionsSelect
var $union : cs.Unions
var $formats; $entité; $sélections; $sélection : Object
var $dataClassNom; $texte; $soustexte; $Code : Text
var $i; $numCode : Integer
var $RacineXML; $ElementXML; $Xpath : Text
// lire les formats
$formats:=New object("Options"; 0)
// options manquantes renseignées _FixerParamètresLibellé
// lire les paramètres
$formats.params:=0
If (OB Is defined($data; "params"))
$formats.params:=$data.params
End if
$formats.séparateurComments:=". "
$texte:=""
Case of
: (Not(OB Is defined($data; "entité")))
: ($data.entité=Null)
Else
$entité:=$data.entité
$dataClassNom:=$entité.DataClassNom
// lire la structure des informations de l'entité $2
$Xpath:=Folder(Get 4D folder(Current resources folder); fk platform path).folder("TemplatesMobileWeb").file("TemplateInfosEntité.xml").platformPath
$RacineXML:=DOM Parse XML source($Xpath)
$ElementXML:=DOM Find XML element by ID($RacineXML; $dataClassNom)
If (ok=1)
ARRAY TEXT($tabElements; 0)
$ElementXML:=DOM Find XML element($ElementXML; "information"; $tabElements)
If (Size of array($tabElements)>0)
// pour chaque info
For ($i; 1; Size of array($tabElements))
// récupérer les éléments de l'info $i
ARRAY TEXT($tabNoms; 1)
ARRAY TEXT($tabValeurs; 1)
// pour les erreurs
$tabNoms{0}:="#Erreur"
$tabValeurs{0}:="#Erreur"
$ElementXML:=DOM Get first child XML element($tabElements{$i}; $tabNoms{1}; $tabValeurs{1})
While (ok=1)
INSERT IN ARRAY($tabNoms; 1; 1)
INSERT IN ARRAY($tabValeurs; 1; 1)
$ElementXML:=DOM Get next sibling XML element($ElementXML; $tabNoms{1}; $tabValeurs{1})
End while
// lire les données nécessaires
$Code:=$tabValeurs{indexTableau(Find in array($tabNoms; "code"))}
// séparateur entre l'information courante et la suivante
$formats.séparateur:=$tabValeurs{indexTableau(Find in array($tabNoms; "separateur"))}
$formats.séparateurBloc:=Choose($data.params ?? 2; "</p><p></br><p>"; $formats.séparateur)
$formats.Options:=Num($tabValeurs{indexTableau(Find in array($tabNoms; "format"))})
If (Match regex("[0-9]{1,5}"; $Code))
// un nombre de 1 à 5 chiffres
$numCode:=Num($code)
Case of
: ($numCode=0)
If ($formats.params ?? 1)
// nom de l'objet de la table courante
$texte:=$texte+$entité.Libellé($formats)+$formats.séparateur
End if
// ajouter le commentaire
$formats.débutComment:=""
$formats.finComment:=Choose($data.params ?? 2; $formats.séparateurBloc; ", ")
$texte:=$texte+$entité.RédigerCommentaire($formats)
: ($numCode=1)
// les membres d'une union
$texte:=$texte+$formats.séparateur+$entité.Libellé($formats)
: ($numCode>=22000) & ($numCode<=22999)
// évents persos
$event:=$entité.EvenementPersonnel($numCode)
If ($event#Null)
// utiliser les formats par défaut
$texte:=$texte+$event.Libellé($formats)
// ajouter le commentaire
$formats.débutComment:=Choose($data.params ?? 2; ". "; ", ")
$formats.finComment:=""
$texte:=$texte+$event.RédigerCommentaire($formats)
$texte:=$texte+$formats.séparateurBloc
End if
: ($numCode>=33000) & ($numCode<=33999)
// évent fam : pour chaque union, éditer le premier Event Fam
// attention : $entité peut concerner différents types de table : chercher la liste des Unions
Case of
: ($dataClassNom="Personnes")
$lesUnions:=$entité.LesUnions()
: ($dataClassNom="Unions")
$lesUnions:=$entité.LesUnions()
Else
$lesUnions:=Null
End case
// pour chaque union de la liste, éditer un event Fam
Case of
: ($lesUnions=Null)
: ($lesUnions.selection.length=0)
Else
// rappel : les unions sont classées par date, et les conjoints sont liés aux unions par [Unions]ID
For each ($union; $lesUnions.selection)
// ajouter l'event, s'il existe
$sélections:=$union.LesEvenementsFamiliaux()
If ($sélections.selection.length=0)
$texte:=$texte+Localized string("33611")
Else
$soustexte:=""
// utiliser les formats par défaut
$formats.Options:=0x3F00
// ici il peut y avoir 1 à plusieurs évents pour cette union (rappel : ordre chronos)
If ($formats.params ?? 3)
// on les prend tous
Else
$sélections:=$sélections.selection.slice(0; 1)
End if
For each ($sélection; $sélections.selection)
$soustexte:=$soustexte+$sélection.Libellé($formats)+$formats.séparateur
End for each
// nettoyer
$texte:=$texte+Substring($soustexte; 1; Length($soustexte)-Length($formats.séparateur))
End if
// ajouter le conjoint , s'il existe
// on aurait pu utiliser l'option 15 du codage de l'évent
Case of
: ($dataClassNom#"Personnes")
: ($union.LeConjoint($entité.ID)=Null)
Else
// ok on a un conjoint
$formats.Options:=35
$texte:=$texte+" "+$union.LeConjoint($entité.ID).Libellé($formats)
End case
// ajouter les commentaires
$soustexte:=""
$formats.débutComment:=Choose($data.params ?? 2; "</p><p>"; ", ")
$formats.finComment:=""
For each ($sélection; $sélections.selection)
$soustexte:=$soustexte+$sélection.RédigerCommentaire($formats)
End for each
$texte:=$texte+$soustexte
$texte:=$texte+$formats.séparateurBloc
End for each
End case
End case
Else
// rien
End if
End for
// nettoyer
//dans cette version pas de nettoyage (les balises vides ne sont pas visibles à l'écran)
End if
End if
DOM CLOSE XML($RacineXML)
End case
// fixer le résultat
$result:="<p>"+$texte+"</p>"
// ----------------------
//MARK:dataClass Wrappers
// ----------------------
Function Libellé($formats : Object)->$libellé : Text
// renvoie le nom formaté de this suivant les options $formats
$libellé:=This.dataClass.Libellé($formats)
Function Le($DataClassNom : Text)->$result : Object
// renvoie l'entité [$DataClassNom] de ce composant (la classe doit exister !)
var $entité : Object
$entité:=This.dataClass.Le($DataClassNom)
// ajouter les attributs / functions WEB
$result:=cs[$DataClassNom].new($entité.ID)
// ----------------------
//MARK:Sélections
// ----------------------
Function Créer()
// créer une collection d'entités ; resultat dans .selection
This.setEntités()
Function setEntités()
// créer la sélection (collection d'entités de this)
var $ID : Integer
This.selection:=New collection
Case of
: (This.DataClassNom="")
: (Not(OB Is defined(This; "collection")))
: (This.collection.length=0)
Else
For each ($ID; This.collection)
This.selection.push(cs[This.DataClassNom].new($ID))
End for each
This.length:=This.selection.length
End case
Function getRelatedEntity($chemin : Text)->$entité : Object
var $c : Collection
var $dataTexte; $lien : Text
// remonter le chemin $chemin de this
$dataTexte:=$chemin
If ($dataTexte="@_@")
$c:=Split string($dataTexte; "_")
// nom de l'attribut de l'end entité
$dataTexte:=$c.pop()
$entité:=This
For each ($lien; $c)
$entité:=$entité[$lien]
End for each
Else
$entité:=This
End if
Function LibelléLié($url : Text; $formats : Object)->$result : Text
// écrire le lien
$result:="<a href="+Char(Double quote)+$url+Char(Double quote)+">"+This.Libellé($formats)+"</a>"
// ----------------------
//MARK:Utilitaires
// ----------------------
Function ThisAjouter($objetORDA : 4D.Class; $nomObjet : Text)
// stocker $classeObjet dans this, sous le nom .nomAttribut
var $new_obj : Object
Use (This)
$new_obj:=This[$nomObjet]
If ($new_obj=Null)
This[$nomObjet]:=New shared object
End if
End use
Use (This[$nomObjet])
This[$nomObjet]:=OB Copy($objetORDA; ck shared; This[$nomObjet])
End use
Function _FixerParamètresLibellé($formats : Object)
// fixer la valeur par défaut des $formats manquant
var $data : Object
var $i : Integer
// valeurs par défaut
$data:=New object("SymbolConjoints"; " & "; "SymbolDateLieu"; ","+Localized string("33"); "FormatDate"; 5; "FormatHeure"; 5; "FormatLieu"; 1; "FormatGeoLoc"; 1)
// compléter $formats
OB GET PROPERTY NAMES($data; $tabNoms)
For ($i; 1; Size of array($tabNoms))
If (Not(OB Is defined($formats; $tabNoms{$i})))
$formats[$tabNoms{$i}]:=$data[$tabNoms{$i}]
End if
End for
Function IDcodé()->$ID : Integer
$ID:=CodeEnreg(This.ID; [This.dataClass.numTable])
⇧
[class]$pageWeb - 02/12/2025 13:16:07
property result : Object
property balisesUrl; paramsUrl; Descripteur : Collection
// propriétés des appelants
property RacineXML : Text
Class extends _composant
Class constructor()
Super()
This.result:=This.InitResult()
//----------------------------------
// MARK:Traitement url
//----------------------------------
Function TraiterURL($url : Text)->$result : Object
// traitement des url internes au serveur (appel des classes $pageXXX par les templates)
// remarque : dans cette version, ces url ont le même format que celles des requêtes client HTTP
This.result.nomMethode:=Current method name
// récupérer les paramètres
This.LireParametresUrl($url)
// normalement .balise[2] est le nom d'une function de $pageXXX
Case of
: (This.balisesUrl=Null)
This.result.Error:=-15068
This.result.ErrorDescription:="url incomplète - pas de balises à traiter"
: (This.balisesUrl.length<3)
This.result.Error:=-15068
This.result.ErrorDescription:="url incorrecte - il manque la paramètres .balise[2]"
: (Not(OB Is defined(This; This.balisesUrl[2])))
This.result.Error:=-15068
This.result.ErrorDescription:="url incorrecte - .balise[2] '"+This.balisesUrl[2]+"' n'est pas une function de this "+OB Class(This).name
Else
// on accepte la demande
// le résultat, s'il y a, est dans this.result.resultat
// exécuter la function, en cas d'erreur elle peut renseigner This.result
This[This.balisesUrl[2]]()
End case
$result:=This.result
Function LireParametresUrl($url : Text)
// $url est de la forme /4Dxxx/yyy/nomFunction {?param1 {+?param2...}}, avec xxx = CGI ou ACTION ou SCRIPT, yyy le contexte WEB, APP ...
// lire les balises
This.balisesUrl:=Split string($url; "/"; sk ignore empty strings)
If (This.balisesUrl.length>0)
// analyser la function
This.paramsUrl:=Split string(This.balisesUrl[This.balisesUrl.length-1]; "?")
// virer function+params
This.balisesUrl:=This.balisesUrl.slice(0; This.balisesUrl.length-1)
// ajouter la function seule
This.balisesUrl.push(This.paramsUrl[0])
// lister les paramètres
This.paramsUrl.shift()
// nettoyer les paramètres
Case of
: (This.paramsUrl.length<2)
// rien à faire
: (This.paramsUrl[0]="@+")
// nettoyer les '+'
This.paramsUrl:=Split string(This.paramsUrl.join(""); "+")
: (This.paramsUrl[0]="@&")
// l'url vient de javascript, le séparateur de params est '&' ('+' ne passe pas)
This.paramsUrl:=Split string(This.paramsUrl.join(""); "&")
End case
Else
This.balisesUrl:=Null
End if
//----------------------------------
// MARK:Connexion
//----------------------------------
Function ServeurActif()
This.result.resultat:=Char(1)+"4D4D"
Function ReConnexion()->$result : Boolean
// renvoie faux si une session user existe, une reconnexion automatique est faite
// renvoie vrai si Guest, ou pas de fichier sessionWeb, ou le timeOut de la session est dépassée (plus d'un an!) ; va lancer la procédure de connexion
var $data : Object
$data:=New object
Case of
: (Not(Session.isGuest()))
// cas normal, la session est active
$result:=False
: (cs.$session.me.getSessionDeCookie($data))
// la session a été fermée et une session enregistrée existe
// la réactiver
$result:=True
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Ré activation Session"; Current method name; $data.infos.session.id)
cs.$session.me.InitialiserSessionInfos($data.infos)
// se reconnecter
This.Envoyer("loginByEmail.shtml"; "accueil")
Else
// ici on est guest ; l'appelant s'occupe de la suite
$result:=False
End case
//----------------------------------
// MARK:Analyse des pages
//----------------------------------
Function isValidDevice()->$result : Boolean
var $request : Object:=New object
$result:=False
This.getWebBrowserInfo($request)
Case of
: (Storage.System.typeApplication=ALV BDD mère)
$result:=True // pour test sur desktop
: (Not(OB Is defined($request; "device")))
: (Not(OB Is defined($request.device; "os")))
: ($request.device.os="iPhone")
$result:=True
: ($request.device.os="Linux")
$result:=($request.device.description="Android@")
// what else?
End case
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Connexion"; Current method name; Choose($result; "OK"; "KO")+" ; device de la requête : "+Choose($result; $request.device.os; "inconnu")+", voir log")
This.trace.EnvoyerMessages([msgk_log]; "Connexion"; Current method name; JSON Stringify($request))
Function getWebBrowserInfo($requete : Object)
var $texte; $subTexte : Text
var $c : Collection
ARRAY TEXT($clésEntête; 0)
ARRAY TEXT($valeursEntête; 0)
WEB GET HTTP HEADER($clésEntête; $valeursEntête)
$requete.device:=New object
$texte:=$valeursEntête{Find in array($clésEntête; "user-Agent")}
$texte:=Substring($texte; Position("("; $texte))
$subTexte:=Substring($texte; 2; Position(")"; $texte)-2)
$c:=Split string($subTexte; ";"; sk trim spaces)
$requete.device.os:=$c[0]
$requete.device.description:=$c[1]
$texte:=Substring($texte; Position("version"; $texte))
$texte:=Substring($texte; Position("/"; $texte)+1)
$requete.device.version:=Substring($texte; 1; Position(" "; $texte)-1)
$texte:=$valeursEntête{Find in array($clésEntête; "Accept-Language")}
$requete.language:=New object
$requete.language.id:=Substring($texte; 1; Position(","; $texte)-1)
$requete.session:=New object
// ici un objet mobileWEB a pour ID de session l'ID du cookie
cs.$cookie.me.Lire()
Case of
: (cs.$cookie.me.liste.length=0)
$requete.session.id:="pas de cookie"
: (cs.$cookie.me.liste.query("nom = :1"; "4DSID@").length=0)
$requete.session.id:="pas de cookie 4DSID"
Else
$requete.session.id:=cs.$cookie.me.liste.query("nom = :1"; "4DSID@")[0].valeur
End case
$requete.session.ip:=$valeursEntête{Find in array($clésEntête; "Host")}
$requete.status:="pending"
//----------------------------------
// MARK:Gestion des pages
//----------------------------------
Function Envoyer($nomPageWeb : Text; $EtatNavigation : Text; $HTTPvars : Text)
// variables process générales
var vs4D; wwwRacineRessources; wwwEtatNavigation; wwwContexteWeb : Text
// fixer les variables process
Use (Session.storage.UserParams)
Session.storage.UserParams.EtatNavigation:=$EtatNavigation
End use
Use (Session.storage.HTTPvars)
Session.storage.HTTPvars.wwwEtatNavigation:=$EtatNavigation
End use
// définir les constantes process (et en mode interprété les variables process)
// restaurer les variables process générales
This.RestaurerHTTPvars("HTTPvars")
// restaurer les variables process spécifiques du contexte (les variables sont déclarées dans ces contextes)
If (Count parameters>2)
This.RestaurerHTTPvars($HTTPvars)
End if
//// fixer le cookie
//If (cs.$cookie.me.getMobileWebCookie()="")
//cs.$cookie.me.Ecrire("mobileWebID"; Session.id)
//End if
//cs.$cookie.me.Ecrire("expire"; "01 Jan "+String(Year of(Current date)+2)+" 00:00:01 GMT")
//cs.$cookie.me.Lire()
WEB SEND FILE($nomPageWeb)
Function Rediriger($url : Text)
WEB SEND HTTP REDIRECT($url)
//----------------------------------
// MARK:Variables process HTTP
//----------------------------------
Function LireHTTPvars()
var $data : Object
var $i : Integer
// depuis v14 les variables Form sont récupérées de cette façon
ARRAY TEXT($tableauDeNoms; 0)
ARRAY TEXT($tableauDeValeurs; 0)
// les variables récupérées correspondent à des objets de formulaire Web ayant un attribut "name"
WEB GET VARIABLES($tableauDeNoms; $tableauDeValeurs)
For ($i; 1; Size of array($tableauDeNoms))
// ne garder que les variables de type wwwXXX...
If ($tableauDeNoms{$i}="www@")
OB SET($data; $tableauDeNoms{$i}; $tableauDeValeurs{$i})
End if
End for
ASSERT(This.trace.DebugerVariables("$commande"; Current method name; New object("variablesHTTP"; $data))) //; "Options"; 0x0002
sharedObject($data; Session.storage.HTTPvars)
Function RestaurerHTTPvars($contexte : Text)
// copier $contexte dans les variables process
var $sessionStorage; $data : Object
var $attribut; $varNom : Text
var $numTable; $numChamp : Integer
var $ptr : Pointer
$sessionStorage:=Session.storage
If (OB Is defined($sessionStorage; $contexte))
$data:=$sessionStorage[$contexte]
For each ($attribut; $data)
RESOLVE POINTER(Get pointer($attribut); $varNom; $numTable; $numChamp)
Case of
: (($numTable=0) & ($numChamp=0))
// pointeur NIL
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Variable indéfinie"; Current method name; $contexte+" : la variable '"+$attribut+"' n'a pas une variable")
: (($numTable#-1) | ($numChamp#-1))
// pas une variable
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Variable indéfinie"; Current method name; $contexte+" : absence de directive de compilation (var "+$attribut+" : xxx")
Else
// on a une variable : l'initialiser
$ptr:=Get pointer($attribut)
$ptr->:=$data[$attribut]
End case
End for each
End if
⇧
[class]Sites - 30/10/2025 17:16:17
property nom : Text
property type : Integer
property lesLieux : cs.LieuxSelect
property laCommune : cs.Communes
Class extends _WEBMO_DataStore
Class constructor($IDentité : Variant)
// initialiser l'objet avec les données de l'entité $IDentité de la BDD
Super("Sites"; $IDentité)
Function FixerParametresListe()->$result : Object
$result:=New object
$result.DataClassNom:="Sites"
$result.Requete:="id>0"
$result.nomFunction:="AfficherFORMdetail"
$result.nomFORMlist:="detailSimple"
Function Libellé($userFormats : Object)->$libellé : Text
$libellé:=This.nom+" ("+This.cFct.LireLocatedSTR(This.type)+")"
Function CreerBDDentity()->$result : Object
$result:=New object
$result.IDunique:=This.IDunique
$result.Elementliste:=This.Elementliste()
// les champs calculés
Super.CreerBDDentity($result; ["Champ_1"; "Champ_2"; "Champ_3"; "Champ_4"; "Champ_titreIconed_1"; "Champ_titreIconed_2"])
// ----------------------
//MARK:Sélection
// ----------------------
Function _LesLieux()
var $selection : cs.LieuxSelect
$selection:=cs.LieuxSelect.new(This.dataClass.LesLieux())
// créer .selection
$selection.Créer()
$selection.selection:=$selection.selection.orderBy("nom asc")
Use (This)
This.lesLieux:=New shared object
End use
This.cFct.AjouterObjetA($selection; This; "lesLieux")
Function _LaCommune()
var $entité : cs.Communes
$entité:=cs.Communes.new(This.dataClass.laCommune)
$entité.Créer()
Use (This)
This.lesLieux:=New shared object
End use
This.cFct.AjouterObjetA($entité; This; "laCommune")
// ----------------------
//MARK: FORM Liste
// ----------------------
Function Elementliste()->$result : Text
$result+="<article id='"+This.IDunique+"' class='element-listeEntity' nom='"+This.nom+"' label='"+This.label+"'>"
$result+="<article>"
$result+=This.LibelléLié(This._tagUrl+"WebDATA/<!--#4DEVAL $1.nomFunction-->?<!--#4DEVAL $1.nomFORMlist-->?Sites?"+This.IDunique; New object("Options"; 0))
$result+="</article>"
$result+="<article class='ListeSites'><ul>"
$result+=This.Events()
$result+="</ul></article>"
$result+="</article>"
Function Events()->$result : Text
var $lieu : cs.Lieux
This._LesLieux()
$result:=""
For each ($lieu; This.lesLieux.selection.orderBy("nom asc"))
$result+="<li>"+$lieu.labeledNom+"</li>"
$result:=$result+$lieu.NombreEvents()
End for each
Function get labeledNom()->$result : Text
$result:=This.nom+" ("+This.label+")"
Function get label()->$result : Text
$result:=This.cFct.LireLocatedSTR(This.type)
// ----------------------
//MARK: FORM Detail
// ----------------------
Function Champ_1()->$result : Text
This._LaCommune()
$result:=This.laCommune.getBlasonURL(This.laCommune.nomFichierIcone)
Function Champ_2()->$result : Text
$result:=This.nom
Function Champ_3()->$result : Text
$result:=This.label
Function Champ_4()->$result : Text
var $lieu : cs.Lieux
This._LesLieux()
$result:="<article class='ListeLieux'><ul>"
For each ($lieu; This.lesLieux.selection)
$result+="<li>"+$lieu.labeledNom+"</li>"
$result+=$lieu.EtatCivil()
$result+="</br>"
End for each
$result+="</article></ul>"
Function Champ_titreIconed_1()->$result : Text
$result:="16830.svg"
Function Champ_titreIconed_2()->$result : Text
$result:=Localized string("152")
⇧
[class]$pageWebDATA - 27/11/2025 17:22:14
property nav : cs.$pageWebNAV
property dataClassValide : Boolean
property DataClassNom : Text:=""
property listeDesEntites : Text:=""
Class extends $pageWeb
Class constructor()
Super()
This.nav:=cs.$pageWebNAV.new()
//----------------------------------
// MARK:Formulaires LISTE
//----------------------------------
Function AfficherFORMliste()
// This.paramsUrl[0] = nom du formulaire liste à envoyer
// This.paramsUrl[1] = nom de la dataClass à utiliser
Case of
: (Not(This.estSessionActive()))
: (This.paramsUrl.length<2)
Else
// cas nominal : tagger la liste
Use (Session.storage.UserParams)
Session.storage.UserParams.Contexte:="ALL"
End use
// fixer la sélection courante
This.nav.setSelectionNavAll(This.paramsUrl[1])
This._AfficherFORMliste()
End case
Function AfficherFORMselection()
// This.paramsUrl[0] = nom du formulaire liste à envoyer
// This.paramsUrl[1] = nom de la dataClass à utiliser
Case of
: (Not(This.estSessionActive()))
: (This.paramsUrl.length<2)
Else
// cas nominal : tagger la liste
Use (Session.storage.UserParams)
Session.storage.UserParams.Contexte:="SELECTION"
End use
// fixer la sélection courante
This.nav.setSelectionNavSelect(This.paramsUrl[1])
This._AfficherFORMliste()
End case
Function RafraichirFORMselection()
This._AfficherFORMliste()
Function _AfficherFORMliste()
// This.paramsUrl[0] = nom du formulaire liste à envoyer
// This.paramsUrl[1] = nom de la dataClass à utiliser
var $nomPageWeb : Text
If (This.paramsUrl.length>1)
$nomPageWeb:=This.paramsUrl[0]+".shtml"
This.Envoyer($nomPageWeb; This.paramsUrl[1])
End if
Function estSessionActive()->$result : Boolean
// renvoyer true si la session est toujours active
$result:=False
Case of
: (This.ReConnexion())
// une session a été activée sur cookie : le logIn a été demandé
// ici soit on est dans une session active (cas nominal, soit on est guest()
: (Session.isGuest())
// on demande une page liste mais on est guest (le cookie ou le fichier session sur Serveur n'existent plus)
This.Envoyer("loginByEmail.shtml"; "accueil")
Else
$result:=True
End case
Function Titrer()
This.result.resultat:=Char(1)+This.Exécuter("Titrer")
Function listerEntities()
var $texte : Text
$texte:=This.InsérerAttente()
Case of
: (Not(This.estDataClassValide()))
: (Not(OB Is defined(cs; This.DataClassNom+"Select")))
This.trace.Créer(-16801; Current method name; "Traitement URL :'la classe "+This.DataClassNom+"Select' n'existe pas").LeverException([msgk_event; msgk_log])
Else
// liste à utiliser
$texte:=This.nav.getListeHTML()
End case
WEB SEND TEXT($texte; "text/html")
Function AfficherCollection()
This.Envoyer("collection.shtml"; This.paramsUrl[0])
Function menuTrier()
var $params; $data : Object
If (This.paramsUrl.length>2)
$params:=cs[This.paramsUrl[1]].new().FixerParametresListe()
If (OB Is defined($params; This.paramsUrl[2]))
// fixer le tri
$data:=Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom]
Use ($data)
$data.tri:=$params[This.paramsUrl[2]]
End use
// ré afficher (utilise paramsUrl[0])
This.RafraichirFORMselection()
End if
End if
//----------------------------------
// MARK:Formulaires DETAIL
//----------------------------------
Function AfficherFORMdetail()
// This.paramsUrl[0] = nom du formulaire detail à envoyer
// This.paramsUrl[1] = nom de la dataClass à utiliser
// This.paramsUrl[2] = UUID de l'entité à afficher
var $nomPageWeb : Text
Case of
: (Not(This.estSessionActive()))
: (This.paramsUrl.length<3)
Else
// mémorisée l'entité sélectionnée
This.nav.setCurrentEntity(This.paramsUrl[1]; This.paramsUrl[2])
// nom de la page à envoyer
$nomPageWeb:=This.paramsUrl[0]+".shtml"
This.Envoyer($nomPageWeb; This.paramsUrl[1])
End case
Function getChamp()
// retourner le champ This.paramsUrl[0] de l'entité courante de la classe courante
var $entité : Object
$entité:=This.nav.getCurrentEntity()
$entité:=Storage.BDD[$entité.DataClassNom].query("IDunique = :1"; $entité.IDunique)[0]
This.result.resultat:=Char(1)+$entité["Champ_"+String(This.paramsUrl[0])]
//----------------------------------
// MARK:Utilitaires
//----------------------------------
Function estDataClassValide()->$result : Boolean
$result:=False
Case of
: (Session=Null)
: (Not(OB Is defined(Session.storage; "UserParams")))
: (Not(OB Is defined(Session.storage.UserParams; "EtatNavigation")))
: (Not(OB Is defined(cs; Session.storage.UserParams.EtatNavigation)))
Else
$result:=True
This.dataClassValide:=$result
This.DataClassNom:=Session.storage.UserParams.EtatNavigation
End case
This.trace.Créer(-16801*Num(Not($result)); Current method name; "Traitement URL :'la classe "+Session.storage.UserParams.EtatNavigation+"' n'existe pas").LeverException([msgk_event; msgk_log])
Function Exécuter($nomFunction : Text)->$result : Text
// appel interne à la classe
$result:=""
Case of
: (Not(This.estDataClassValide()))
: (Not(OB Is defined(cs[This.DataClassNom].new(); $nomFunction)))
// function inconnue
This.trace.Créer(-16801; Current method name; "Traitement URL :'"+$nomFunction+"' n'est pas une function de la classe '"+This.DataClassNom+"'").LeverException([msgk_event; msgk_log])
Else
$result:=cs[This.DataClassNom].new()[$nomFunction]()
End case
Function InsérerAttente()->$result : Text
var $texte : Text
$texte:=Folder(fk resources folder).folder("TemplatesPagesWeb").file("attente.html").getText()
$texte:=Replace string($texte; Char(Line feed); "")
$texte:=Replace string($texte; " "; "")
$texte:=Substring($texte; Position("<body>"; $texte)+Length("<body>"))
$texte:=Substring($texte; 1; Position("</body>"; $texte)-1)
PROCESS 4D TAGS($texte; $result)
⇧
[class]$albums - 26/11/2025 09:14:45
// _albums est indépendant des actions mobile
property webALB : cs.xALB.$pageWebAlbum
property reqALB : cs.xALB.$pageWebREQUETE
property UserParams : Object
Class extends $serveur
Class constructor($url : Text)
Super()
This.LireParametresUrl($url)
// récupérer le nom de la function
Case of
: (This.balisesUrl=Null)
: (This.balisesUrl.length<3)
Else
This.url:=This.balisesUrl[2]
End case
This.InitSession()
This.UserParams:=Session.storage.ALB_UserParams
// on va utiliser les functions de ALB
This.webALB:=cs.xALB.$pageWebAlbum.new($url)
This.reqALB:=cs.xALB.$pageWebREQUETE.new($url)
Function labelDataClass()->$result : Text
$result:=Uppercase("l'album")
Function InitSession()
Super.InitSession("ALB")
// paramètres propres ALB
Case of
: (Session=Null)
: (Not(OB Is defined(Session; "storage")))
Else
If (Not(OB Is defined(Session.storage; "ALB_UserParams")))
Use (Session.storage)
Session.storage.ALB_UserParams:=New shared object
End use
End if
// fixer le récepteur des albums
If (Not(OB Is defined(Session.storage.ALB_UserParams; "Albums")))
Use (Session.storage.ALB_UserParams)
Session.storage.ALB_UserParams.Albums:=New shared collection
End use
End if
// passer à ALB les noms de function / page html utilisés ici
Use (Session.storage.ALB_Data)
Session.storage.ALB_Data.urlOuvrirALB:="/$albums/OuvrirAlbum"
Session.storage.ALB_Data.urlVisualiserALB:="/$albums/VisualiserAlbum"
Session.storage.ALB_Data.pageAccueilALB:="mobileAlbumsAccueil.shtml"
Session.storage.ALB_Data.pageVisuALB:="mobileAlbumVisualiser.shtml"
Session.storage.ALB_Data.avecContact:=False
End use
End case
// -----------------------------
// MARK:Traitement des URL albums
// point d'entrée des traitements et autres ALB
// -----------------------------
Function Traiter()->$result : Boolean
$result:=False
Case of
: (This.url="")
: (Not(OB Is defined(This; This.url)))
// l'url est autre chose qu'une function de this ; laisser passer
Else
$result:=True
// exécuter l'url
This[This.url]()
End case
Function mobileAlbumsConnecter()->$result : Boolean
// envoyer la page de la liste des albums
This.Envoyer(Session.storage.ALB_Data.pageAccueilALB; "Albums")
$result:=True
Function OuvrirAlbum()->$result : Boolean
// envoyer la page des vignettes de l'album sélectionné
This.webALB.OuvrirAlbum()
$result:=True
// fixer les variables process (ID de l'album ouvert)
Use (Session.storage.UserParams)
Session.storage.UserParams.EtatNavigation:="ALB_"+This.paramsUrl[0]
End use
Function VisualiserAlbum()->$result : Boolean
This.webALB.VisualiserAlbum()
$result:=True
Function Envoyer($nomPageWeb : Text; $EtatNavigation : Text)
// fixer les variables process
// pour ici
Use (Session.storage.UserParams)
Session.storage.UserParams.EtatNavigation:=$EtatNavigation
End use
// pour le composant ALB
Use (Session.storage.ALB_HTTPvars)
Session.storage.ALB_HTTPvars.wwwEtatNavigation:="Accueil"
End use
WEB SEND FILE($nomPageWeb)
// -----------------------------
// MARK:Elements HTML spécifiques MOB
// -----------------------------
Function LireSTR()->$result : Text
$result:=""
If (This.paramsUrl.length>0)
$result:=Localized string(This.paramsUrl[0])
End if
$result:=Char(1)+$result
Function ListerAlbums()->$result : Text
var $dossiers : Collection
$dossiers:=cs._document.new().getWEBalbumsFolder().folders()
This.webALB.Lister($dossiers)
$result:=This.webALB.result.resultat
// -----------------------------
// MARK:Requete HTML
// -----------------------------
Function mobileAlbumAjouterNote()
// traiter la requete
// les données sont dans le corps
var $corps : Text
var $data; $requete : Object
$requete:=New object("success"; False; "EntitéRéduite"; New object)
ARRAY TEXT($tabChamps; 0)
ARRAY TEXT($tabValeurs; 0)
WEB GET HTTP HEADER($tabChamps; $tabValeurs)
Case of
: (Find in array($tabChamps; "Content-Type")=-1)
: ($tabValeurs{Find in array($tabChamps; "Content-Type")}#"application/json")
Else
// ok on a reçu un objet
WEB GET HTTP BODY($corps)
$data:=JSON Parse($corps)
Case of
: (Not(OB Is defined($data; "indexMedia")))
: (Not(OB Is defined($data; "note")))
: (Not(OB Is defined($data.note; "objet")))
: (Not(OB Is defined($data.note; "contenu")))
Else
$requete.success:=True
$requete.EntitéRéduite.DataClassNom:="ALB_"+Session.storage.ALB_UserParams.Album.Identification_ID
$requete.EntitéRéduite.IDunique:=Session.storage.ALB_UserParams.Album.Medias[$data.indexMedia].MED_IDunique
$requete.EntitéRéduite.params:=$data.note
//TODOcs.$notes.new($requete).EcrireNote()
End case
End case
WEB SEND TEXT("traitement "+Choose($requete.success; "OK"; "KO"))
⇧
[class]Unions - 03/12/2025 11:19:50
property leEvent : cs.Events
property lesMembres : Object
// attributs de la classe
property SansEnfant : Boolean
Class extends _WEBMO_DataStore
Class constructor($IDentité : Variant)
// initialiser l'objet avec les données de l'entité $IDunique de la BDD
var $c : Collection
Super("Unions"; $IDentité)
// pour trier les unions, mettre l'event ici
// attention il peut ne pas y en avoir
This.leEvent:=Null
$c:=This.dataClass.LesEvents()
// prendre le premier
If ($c.length>0)
This.leEvent:=cs.Events.new($c[0])
End if
Function Libellé($formats : Object)->$result : Text
// renvoie le nom formaté des protagonistes suivant les options $formats
// $formats
// l'union (parentale par exemple) peut être nulle
var $sélection : cs.PersonnesSelect
var $entité : cs.Personnes
var $lien : Text
If (This.ID#0)
// sélectionner les membres de l'union
$sélection:=This.LesProtagonistes()
// coder leur noms
$result:=""
$lien:=" & "
For each ($entité; $sélection.selection)
$result:=$result+$lien+$entité.Libellé($formats)
End for each
// nettoyer
$result:=Replace string($result; $lien; ""; 1)
End if
// ----------------------
//MARK:Sélection
// ----------------------
Function LesEvenementsFamiliaux()->$result : cs.EventsSelect
// créer la collection des events triée par date
$result:=cs.EventsSelect.new(This.dataClass.LesEvents())
$result.Créer()
$result.selection:=$result.selection.orderBy("dateNum asc")
Function LesProtagonistes()->$result : cs.PersonnesSelect
// créer la sélection de personnes
var $c : Collection
$result:=cs.PersonnesSelect.new(This.dataClass.LesProtagonistes())
// ordonner les protagonistes : membre1 = homme, membre2 = femme
$result.Créer()
$c:=$result.selection // le personnes
This.lesMembres:=New object
// rappel : homme sexe = faux, femme sexe = vrai
// plusieurs cas
Case of
: ($c.length=0)
This.lesMembres:=Null
: ($c.length=1)
This.lesMembres.membre1:=Null
This.lesMembres.membre2:=Null
If ($c[0].sexe)
This.lesMembres.membre2:=$c[0]
Else
This.lesMembres.membre1:=$c[0]
End if
Else
$c:=$c.orderBy("sexe asc")
This.lesMembres.membre1:=$c[0]
This.lesMembres.membre2:=$c[1]
End case
Function LeConjoint($ID : Integer)->$result : Object
// trouver les membres de l'union
This.LesProtagonistes()
Try
// chercher dans les membres celui dont l'ID n'est pas $ID
If (This.lesMembres.membre1.ID=$ID)
$result:=This.lesMembres.membre2
Else
$result:=This.lesMembres.membre1
End if
Catch
// conjoint absent
$result:=Null
End try
⇧
[class]$serveur - 01/03/2026 13:01:40
// pour optimiser les appels, cette classe n'étend pas $composant
property trace : cs._Trace
property fct : cs.xSDK.Outils
property rsc : cs.xSDK.ResourceALV
property balisesUrl; paramsUrl : Collection
// utiliser par les composants
property url : Text:=""
property result : Object:=Null
Class constructor()
This.trace:=cs._Trace.me
This.fct:=cs.xSDK.Outils.me
This.rsc:=cs.xSDK.ResourceALV.me
// ----------------------
//MARK:Serveur
// ----------------------
Function Demarrer()
var $data; $params; $result : Object
var $c : Collection
var $webServer : 4D.WebServer
$c:=WEB Server list.query("name = :1"; Storage.ServeurHTTP.nom)
Case of
: ($c.length=0)
// pas de serveur ; le créer (test du composant)
$webServer:=WEB Server(Web server database)
: ($c[0].isRunning)
// déjà démarré ; abandonner
$webServer:=Null
Else
// récupérer le serveur
$webServer:=$c[0]
End case
If ($webServer=Null)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance Serveur Web"; Current method name; "Le serveur Web est déjà démarré")
Else
// fixer les paramètres généraux du serveur Web
$data:=New object
This.FixerParametres($data)
// par défaut, pas de certificat => pas https
// Enable HTTP on your 4D Web server (no certificates)
$data.HTTPEnabled:=True
// Disable HTTPS on your 4D Web server
$data.HTTPSEnabled:=False
$data.HSTSEnabled:=False
// état du certificat SSL
$params:=cs._document.new().CertInformations()
Case of
: (Not($params.Production.exists))
// on n'a pas de certificat SSL
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Paramétrage Serveur Web : Cert"; Current method name; "certificat SSL en production non trouvé")
: ($params.Production.Invalide)
// on n'a pas de certificat SSL valide
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Paramétrage Serveur Web : Cert"; Current method name; "certificat SSL trouvé en production non valide, doit être renouvelé")
Else
// options HTTPS
// age maximal d'activation du HSTS pour une session
$data.HSTSMaxAge:=7776000 // 7 776 000 = 3 * 30 * 24 * 3600, soit 3 mois. 31 536 000 = 365 * 86400 s = 365 days
// Enable HSTS on the 4D Web server
// rappel : HSTS activé permet au serveur web 4D de déclarer que les navigateurs ne doivent interagir avec lui que par des connexions HTTPS sécurisées
// important : ici HTTP est aussi activé : le navigateur peut toujours basculer entre HTTPS et HTTP (par exemple, dans la zone URL du navigateur, l'utilisateur peut remplacer "https" par "http")
// on pourra déactiver HTTP
$data.HSTSEnabled:=True
// Enable HTTP on your 4D Web server
$data.HTTPEnabled:=True
// Enable HTTPS on your 4D Web server
$data.HTTPSEnabled:=True
End case
// fixer le point d'entrée du site
This.InstallerURLdémarrage("mobile")
// c'est ok, on démarre
This.trace.EnvoyerMessages([msgk_log]; "Serveur Web"; Current method name; "$data "+JSON Stringify($data))
$result:=$webServer.start($data)
// message ALV
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "dossier racine Web"; Current method name; "<"+$data.rootFolder.platformPath+">")
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Démarrage"; Current method name; "Le serveur Web "+Choose($webServer.HTTPSEnabled; "[HTTPS]"; "[HTTP]")+" est démarré "+Choose($webServer.isRunning; "[OK]"; "[KO]")+", HSTS "+Choose($webServer.HSTSEnabled; "[OK]"; "[KO]"))
End if
Function Arreter()
var $vb_stopped : Boolean
If (WEB Server(Web server database).isRunning)
ASSERT(This.trace.DebugerMethode("Stop"; Current method name; "stopping web server..."))
WEB Server(Web server database).stop()
End if
$vb_stopped:=Not(WEB Server(Web server database).isRunning)
ASSERT($vb_stopped; "web server failed to stop")
ASSERT(This.trace.DebugerMethode("Stop"; Current method name; "web server stopped. "+Choose($vb_stopped; "[OK]"; "[KO]")))
// message ALV
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance Serveur Web"; Current method name; "Le serveur Web est arrêté "+Choose($vb_stopped; "[OK]"; "[KO]"))
Function FixerParametres($params : Object)
// fixer les paramètres du serveur Web de ce composant
var $dataEntier : Integer:=0
var $adresseIP : Text
var $dossier : 4D.Folder
// l'adresse IP du serveur Web 4D : lire l'adresse IP de la machine sur le réseau
$adresseIP:=cs.xSDK.EnvironnementALV.new().infosSystème().IPadresse
This.rsc.SetResourceALV(Est Ressource WEBMO; "Serveur_web/Web_Adresse_IP_ecoute"; ->$adresseIP)
$params.IPAddressToListen:=$adresseIP
// fixer les options APP
// surcharge les valeurs définies dans les propriétés de la base
This.rsc.SetVariable(Est Ressource WEBMO; "Serveur_web/portHTTP_sousDomaine"; Is longint; ->$dataEntier)
$params.HTTPPort:=$dataEntier
This.rsc.SetVariable(Est Ressource WEBMO; "Serveur_web/portHTTPS_sousDomaine"; Is longint; ->$dataEntier)
$params.HTTPSPort:=$dataEntier
This.rsc.SetVariable(Est Ressource WEBMO; "Serveur_web/Web_Timeout_process"; Is longint; ->$dataEntier)
$params.inactiveProcessTimeout:=$dataEntier
This.rsc.SetVariable(Est Ressource WEBMO; "Serveur_web/Web_Timeout_session"; Is longint; ->$dataEntier)
$params.inactiveSessionTimeout:=$dataEntier
$params.scalableSession:=True
//$params.sessionCookieName:="ALV_WEBmobile" // "" rétablit la valeur par défaut (4DSID)
// fixer le dossier des certificats
$dossier:=cs._document.new().getCertificatSSLFolder()
If ($dossier.exists)
$params.certificateFolder:=$dossier
End if
// fixer le dossier racine
$dossier:=cs._document.new().getRacineHTMLFolder()
If ($dossier.exists)
$params.rootFolder:=$dossier
End if
Function InstallerURLdémarrage($nomPage : Text)
var $fichier; $fileFTP : 4D.File
var $result : cs.xSDK.Traces
var $texteOUT : Text
var $texteIN:=""
var $data : Object
$data:=New object
// fixer l'url du point d'entrée du serveur ; 2 cas : opérationnel et test local
This.rsc.SetObjet(Est Ressource WEBMO; "Serveur_web/portHTTPS_sousDomaine"; Is longint; $data; "port")
$data.adresse:=This.getAdresseServeur()
$data.nomPage:=Choose(Storage.System.typeApplication=ALV Serveur APP; $nomPage+".html"; $nomPage+"test.html")
$data.url:="https://"+$data.adresse+":"+String($data.port)+"/4DCGI/WebLOGIN/seConnecter"
$fileFTP:=cs.xSDK.Traces.new().GetGarbageDossier().folder("_WEBMOdebug").file($data.nomPage)
$fichier:=Folder(fk resources folder).folder("TemplatesMobileWeb").file($nomPage+"Proto.html")
If ($fichier.exists)
$texteIN:=$fichier.getText()
PROCESS 4D TAGS($texteIN; $texteOUT; $data)
$fileFTP.setText($texteOUT)
// transfert sur l'hébergeur
This.rsc.SetObjet(Est Ressource HOST; "Chemins/siteWEBstatique/Path"; Is text; $data; "url")
$result:=cs.xSDK.ServicesFTP.new().EnvoyerFichier($fileFTP.platformPath; $data.url)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Intégration "+Choose($result.success; "[OK]"; "[KO]"); Current method name; "URL racine Web installée sur hébergeur : '"+$data.url+"'")
End if
Function getAdresseServeur()->$result : Text
var $dataTexte : Text:=""
If (Storage.System.typeApplication=ALV Serveur APP)
// url du serveur WEB opérationnel
This.rsc.SetVariable(Est Ressource APP; "serveur_URL/Nom_sousDomaine"; Is text; ->$dataTexte)
Else
// pour test
This.rsc.SetVariable(Est Ressource WEBMO; "Serveur_web/Web_Adresse_IP_ecoute"; Is text; ->$dataTexte)
End if
$result:=$dataTexte
Function LireInformationsServeur()->$result : Object
// informations du serveur Web
var $dataTexte : Text:=""
var $i : Integer:=0
var $texte : Text
// en principe : ALV Serveur APP est interrogé par ALV Client APP, et ALV Serveur HTTP par 4D mode distant
$result:=New object
// *** les paramètres
$result.params:=New object
// dossier racine
$result.params.DossierRacineHTML:=Get 4D folder(HTML Root folder; *) //Lire Ressource ALV(Est Ressource WEB; "Chemins/Serveur_web/Dossier_racine_web"; Est un texte)->
$result.params.estDémarré:=WEB Is server running
// paramètres
WEB GET OPTION(Web port ID; $i)
$result.params.webPortID:=$i
WEB GET OPTION(Web HTTPS port ID; $i)
$result.params.webHTTPSPortID:=$i
WEB GET OPTION(Web HTTPS enabled; $i)
$result.params.HTTPSEnabled:=($i=1)
WEB GET OPTION(Web HSTS enabled; $i)
$result.params.HSTSEnabled:=($i=1)
// URL serveur
This.rsc.SetVariable(Est Ressource APP; "serveur_URL/Nom_sousDomaine"; Is text; ->$dataTexte)
$texte:="://"+$dataTexte
If ($result.params.HTTPSEnabled)
$texte:="https"+$texte
This.rsc.SetVariable(Est Ressource WEBMO; "Serveur_web/portHTTPS_sousDomaine"; Is longint; ->$i)
$texte:=$texte+":"+String($i)
Else
$texte:="http"+$texte
This.rsc.SetVariable(Est Ressource WEBMO; "Serveur_web/portHTTP_sousDomaine"; Is longint; ->$i)
$texte:=$texte+":"+String($i)
End if
$result.params.URLserveurWEB:=$texte
// *** info serveur composant
$result.serveurWeb:=WEB Server(Web server database)
// au cas ou, passer en objet pur
$dataTexte:=JSON Stringify($result)
$result:=JSON Parse($dataTexte)
// ----------------------
//MARK:Connexions
// ----------------------
Function surAuthentificationWeb($url : Text; $entete : Text; $IPnavigateur : Text; $IPserveur : Text; $LogIn : Text; $motDePasse : Text)->$result : Boolean
// Appelée à la réception d'une 4Daction (4DSCRIPT...), d'une url 4DCGI (pas seulement?)
// retourne toujours vrai sinon ; l'action est validée
// fixe un .userInfo pour la suite des opérations (vide = pas d'utilisateur identifié)
var $data : Object
var $pageWeb : cs.$pageWeb
// pour les erreurs
cs._CommunFunctions.me.InitProcess()
$data:=New object
$data.Commande:=$url
$data.IPnavigateur:=$IPnavigateur
$data.utilisateur:=$LogIn
ASSERT(This.trace.DebugerVariables($url; Current method name; $data)) //; "Options"; 0x0002
$pageWeb:=cs.$pageWeb.new()
// normalement toujours vrai
$result:=True
Case of
: (cs.$session.me.getTokenFromSession()#"")
// une session est en cours et active
: (cs.$session.me.getSessionDeCookie($data))
// le cookie pointe une session enregistrée ; on a récupéré ses infos dans .infos
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Ré ouverture de la session"; Current method name; $data.infos.session.id+" (voir infos dans logs)")
This.trace.EnvoyerMessages([msgk_log]; "Ré ouverture de la session"; Current method name; JSON Stringify($data.infos))
: (Session.isGuest())
// ouverture par invité Web ; ses données
// ici session.userName vaut "", Session.isGuest()=vrai
cs.$session.me.InitUserData()
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Session Guest"; Current method name; "Session id "+Session.id+" - idleTimeout "+String(Session.idleTimeout)+" - expirationDate "+String(Session.expirationDate))
Else
// what else?
$result:=False
End case
// mettre à jour le contexte
$pageWeb.InitContexte()
// initialiser les variables process
// dont vs4D : prévenir le navigateur que le serveur est présent (à faire tout de suite)
$pageWeb.RestaurerHTTPvars("HTTPvars")
// attention : ici, v7.4.5, un ASSERT(DEBUG ALV (Storage.System;"REQUEST:TRACE_VARIABLE"... empêche celui de "sur connexion Web"
//TracerSession(Créer objet("méthode"; Nom méthode courante; "url"; $url; "$0"; Chaîne($0)))
Function surConnexionWeb($url : Text; $entete : Text; $adresseIPnavigateur : Text; $adresseIPserveur : Text; $LogIn : Text; $motDePasse : Text)
// init du process Web (le process de la session peut avoir changé)
cs._CommunFunctions.me.InitProcess()
// essayer une url ALV
// Compiler_Web n’a pas été appelé, toutes les variables et sélections existent
Case of
// essayer de traiter toutes les url envoyées par le client HTTP
: (cs.$authentificationEmail.new().ActiverSession($url))
// ok le mobile User est authentifié
: (This.TraiterURLpage($url))
// commande traitée
: (This.TraiterURLaction($url))
// commande traitée
// // essayer les commandes des composants :
// essayer les commandes des albums
: (cs.xALB.$serveurWeb.new().ConnexionWeb($url; $entete; $adresseIPnavigateur; $adresseIPserveur; $LogIn; $motDePasse))
// commande traitée
// filtrer certaines erreurs
: ($url="/ressources@")
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Serveur Web"; Current method name; "L'url '"+$url+"' n'est pas traitée")
: (Session=Null)
// on n'est pas sur le serveur Web
Else
// commande inconnue, retour à la case départ
cs._Trace.me.DebugerMethode($url; Current method name; $url+" : commande 4DCGI inconnue")
End case
cs._Trace.me.Session(Current method name; $url)
// ----------------------
// MARK:Traitement des url
// ----------------------
Function TraiterURLpage($url : Text)->$result : Boolean
// traiter toutes les url envoyées par un formulaire en construction
// remarque : ces url adressent la BDD
// transmettre l'url à la bonne classe $page pour traitement
This.result:=This.InitResult(0; ""; False)
This.result.nomMethode:=Current method name
This.result.resultat:=""
// analyser l'url
This.LireParametresUrl($url)
Case of
: (This.balisesUrl=Null)
This.result.Error:=-15068
This.result.ErrorDescription:="url incomplète - pas de balises à traiter"
: (This.balisesUrl.length<2)
This.result.Error:=-15068
This.result.ErrorDescription:="url incomplète - le contexte de $page, balisesUrl[2], est absent"
: (Not(OB Is defined(cs; "$page"+This.balisesUrl[1])))
// url non traitée ici
This.result.Error:=-15068
This.result.ErrorDescription:="url incomplète - la classe $page"+This.balisesUrl[1]+" est inconnue"
Else
// créer la classe et traiter l'url
// le résultat, s'il y a, est dans $result.resultat
// en cas d'erreur elle peut renseigner $result
This.result:=cs["$page"+This.balisesUrl[1]].new().TraiterURL($url)
End case
This.result.success:=(This.result.Error=0)
$result:=This.result.success
Function TraiterURLaction($url : Text)->$result : Boolean
// traiter toutes les url liées à des actions
// remarque : ces url concernent les albums, carto, arbres et notes
// transmettre l'url à la bonne classe pour traitement
$result:=True
Case of
: (cs.$albums.new($url).Traiter())
// url traité par l'album
: (cs.$action.new().TraiterURL($url))
// url traité par le serveur
Else
// pas concerné !
$result:=False
End case
Function LireParametresUrl($url : Text)
// $url est de la forme /4Dxxx/yyy/nomFunction {?param1 {+?param2...}}, avec xxx = CGI ou ACTION ou SCRIPT, yyy le contexte WEB, APP ...
// lire les balises
This.balisesUrl:=Split string($url; "/"; sk ignore empty strings)
If (This.balisesUrl.length>0)
// analyser la function
This.paramsUrl:=Split string(This.balisesUrl[This.balisesUrl.length-1]; "?")
// virer function+params
This.balisesUrl:=This.balisesUrl.slice(0; This.balisesUrl.length-1)
// ajouter la function seule
This.balisesUrl.push(This.paramsUrl[0])
// lister les paramètres
This.paramsUrl.shift()
// nettoyer les paramètres
Case of
: (This.paramsUrl.length<2)
// rien à faire
: (This.paramsUrl[0]="@+")
// nettoyer les '+'
This.paramsUrl:=Split string(This.paramsUrl.join(""); "+")
: (This.paramsUrl[0]="@&")
// l'url vient de javascript, le séparateur de params est '&' ('+' ne passe pas)
This.paramsUrl:=Split string(This.paramsUrl.join(""); "&")
End case
Else
This.balisesUrl:=Null
End if
//----------------------------------
// MARK:Utilitaires
//----------------------------------
Function InitResult($Error : Integer; $ErrorDescription : Text; $success : Boolean)->$result : Object
If (Count parameters=0)
$Error:=0
$ErrorDescription:=""
$success:=True
End if
$result:=New object("Error"; $Error; "ErrorDescription"; $ErrorDescription; "success"; $success)
$result.nomMethode:=Current method name
Function InitSession($portée : Text)
// paramètres communs à tous les contextes
Case of
: (Session=Null)
// en test par exemple
: (Not(OB Is defined(Session; "storage")))
// pourquoi ?
Else
If (Not(OB Is defined(Session.storage; $portée+"_HTTPvars")))
Use (Session.storage)
// tous les attributs de $portée_HTTPvars sont des noms de variables process
Session.storage[$portée+"_HTTPvars"]:=New shared object
// les autres données
Session.storage[$portée+"_Data"]:=New shared object
End use
End if
End case
⇧
[class]$pageWebITEM - 06/11/2025 11:42:56
Class extends $pageWeb
Class constructor()
Super()
Function LireSTR()
var $params : Object
This.result.resultat:="#err LireSTR"
If (This.paramsUrl.length>0)
$params:=New object
If (This.paramsUrl.length>1)
$params.genre:=(Position("féminin"; This.paramsUrl[1]; *)>0)
$params.plur:=(Position("pluriel"; This.paramsUrl[1]; *)>0)
End if
// le nom de l'apps peut être utilisé dans les chaines
This.rsc.SetObjet(Est Ressource APP; "Ressources_Communes/Nom_Application"; Is text; $params; "param_1")
This.paramsUrl.push("")
This.result.resultat:=This.cFct.LireLocatedSTR(Num(This.paramsUrl[0]); $params)
End if
This.result.resultat:=Char(1)+This.result.resultat
Function urlServeurWeb()
var $texte : Text:=""
This.rsc.SetVariable(Est Ressource APP; "Serveurs_ALV/IP_Serveur"; Is text; ->$texte)
This.result.resultat:=Char(1)+$texte
Function adressServeurWeb()
var $texte : Text:=""
This.rsc.SetVariable(Est Ressource APP; "Serveurs_ALV/Adresse_serveur"; Is text; ->$texte)
This.result.resultat:=Char(1)+$texte
⇧
[class]UtilisateursALV - 04/10/2025 09:35:22
// attributs de la classe
property Password; AdresseEmail : Text
Class extends _WEBMO_DataStore
Class constructor($IDentité : Variant)
// initialiser l'objet avec les données de l'entité $IDentité de la BDD
Super("UtilisateursALV"; $IDentité)
⇧
[class]DicoDesNomsSelect - 04/10/2025 09:35:46
Class extends _WEBMO_DataStore
Class constructor($requête : Variant)
Super("DicoDesNomsSelect"; $requête)
// ----------------------
//MARK:HTML
// ----------------------
Function Ecrire()->$result : Text
var $c : Collection
var $ID : Integer
// créer la sélection, ici on fait simple, pas de table [DicoDesNoms]
$c:=New collection
For each ($ID; This.collection)
$c.push(cs.xSQL.DicoDesNoms.new($ID).patronyme)
End for each
$c:=$c.distinct().orderBy("asc")
$result:="<p>"
$result+=Localized string("154")
$result+="</p></br>"
$result+="<p>"
$result+=$c.join(", ")
$result+="</p>"
⇧
[class]_maintenance - 04/06/2026 15:28:57
property nomTache : Text:="MaintenanceWEBMO"
property tache : cs.xSDK.Tache
property Taches : Collection
property listeDataClass : Collection
Class extends _composant
Class constructor()
Super()
This.listeDataClass:=New collection("Personnes"; "Communes"; "Medias"; "Sites")
// -----------------------------
// MARK:Maintenance
// -----------------------------
Function FixerListeTâches()
// lister les tâches à exécuter
var $data : Object
This.Taches:=New collection
$data:=New object
$data.functionID:="MettreAjourBDDmobile"
// prochaine nuit à 4:30
$data.dateTache:=String(Add to date(Current date; 0; 0; 1); ISO date GMT; ?04:30:00?)
// tous les jours
$data.période:=New object("jour"; 1; "seconde"; 0)
$data.initialiser:=True
This.Taches.push(OB Copy($data))
This.trace.EnvoyerMessages([msgk_event]; "Maintenance"; Current method name; "tâche 'MettreAjourBDDmobile' programmée (voir détails dans Logs)")
This.trace.EnvoyerMessages([msgk_log]; "Maintenance ChargerBDDmobile"; Current method name; JSON Stringify($data))
$data:=New object
$data.functionID:="CréerMediaMobile"
// prochaine nuit à 4:30
$data.dateTache:=String(Add to date(Current date; 0; 0; 1); ISO date GMT; ?04:35:00?)
// tous les jours
$data.période:=New object("jour"; 1; "seconde"; 0)
$data.initialiser:=True
This.Taches.push(OB Copy($data))
This.trace.EnvoyerMessages([msgk_event]; "Maintenance"; Current method name; "tâche 'CréerMediaMobile' programmée (voir détails dans Logs)")
This.trace.EnvoyerMessages([msgk_log]; "Maintenance CréerMediaMobile"; Current method name; JSON Stringify($data))
$data:=New object
$data.functionID:="InstallerAlbums"
// prochaine nuit à 5:00
$data.dateTache:=String(Add to date(Current date; 0; 0; 1); ISO date GMT; ?05:00:00?)
// tous les jours
$data.période:=New object("jour"; 1; "seconde"; 0)
$data.initialiser:=True
This.Taches.push(OB Copy($data))
This.trace.EnvoyerMessages([msgk_event]; "Maintenance"; Current method name; "tâche 'InstallerAlbums' programmée (voir détails dans Logs)")
This.trace.EnvoyerMessages([msgk_log]; "Maintenance InstallerAlbums"; Current method name; JSON Stringify($data))
Function Démarrer()
// exécuter dans un process externe
var $data : Object
var $numProc : Integer
Case of
: ((Storage.System.typeApplication#ALV Serveur APP)) & (Not(Storage.Host.$application.call(Null).estDebugAPP()))
// serveur ALV seul uniquement ou debug
Else
$data:=New object
$data.functionID:="SuperviserLesTaches"
$data.nomTache:=This.nomTache
$data.numProcessAppelant:=-1
$numProc:=ExecuteFunctionPreemptive(cs._maintenance; $data)
End case
Function Arrêter()
cs.xSDK.RegistreTaches.new().Tuer(This.nomTache)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance"; Current method name; "Arrêt du monitoring")
Function SuperviserLesTaches($data : Object)
// gérer les tâches de la maintenance des sessions et données mobiles
var $tâche : Object
var $jours : Integer
var $heure : Integer
This.tache:=$data.tache
// tempo de 1 mn, que l'installation du serveur soit terminée
Waiting(60*60)
TRACE
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance"; Current method name; "Démarrage du monitoring")
This.FixerListeTâches()
// lancer le monitoring des tâches
Repeat
For each ($tâche; This.Taches)
Case of
: (Not(OB Is defined($tâche; "functionID")))
: (Not(OB Is defined($tâche; "dateTache")))
: (Not(OB Is defined($tâche; "initialiser")))
: (Not(($tâche.initialiser) | (String(Current date; ISO date GMT; Current time)>$tâche.dateTache)))
// attendre
Else
// ok, on a tout pour cette tâche
This[$tâche.functionID]()
// date de la prochaine maintenance
// nombre de jours
// on peut avoir rater des périodes ; combien?
$jours:=Current date-Date($tâche.dateTache)
// ajouter la période
$jours:=$jours+$tâche.période.jour+((Time($tâche.dateTache)+$tâche.période.seconde)\(24*3600))
// nouvelle heure
$heure:=Mod(Time($tâche.dateTache)+$tâche.période.seconde; 24*3600)
// nouvelle date (au cas où, on se resynchronise aussi sur l'heure)
$tâche.dateTache:=String(Add to date(Date($tâche.dateTache); 0; 0; $jours); ISO date GMT; Time($heure))
$tâche.initialiser:=False
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance"; Current method name; "La tâche '"+$tâche.functionID+"' sera relancée le '"+$tâche.dateTache+"'")
End case
End for each
// *** attendre la période suivante
Waiting(60*10)
Until (This.tache.Tuer.signaled)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance"; Current method name; "Arrêt du monitoring")
// -----------------------------
// MARK:DataBase
// -----------------------------
Function ChargerBDDmobile()
var $dossier : 4D.Folder
var $fichier : 4D.File
var $dataClassNom : Text
var $c : Collection
// initialiser le storage ; on doit avoir un dossier
$dossier:=cs._document.new().getBDDFolder()
If (Not($dossier.exists))
$dossier.create()
End if
// charger la base de données locale (sur disque) dans Storage.BDD
// avec ce qui existe dans ce dossier
For each ($dataClassNom; This.listeDataClass)
$fichier:=cs._document.new().getBDDFolder().file($dataClassNom+".json")
If ($fichier.exists)
$c:=JSON Parse($fichier.getText(); Is collection)
// stocker
Use (Storage.BDD)
Storage.BDD[$dataClassNom]:=New shared collection
End use
sharedCollection($c; Storage.BDD[$dataClassNom])
End if
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance"+Choose($fichier.exists; " [OK]"; " [KO]"); Current method name; "Lecture du fichier de la DataClass "+$dataClassNom+" : "+$fichier.platformPath)
End for each
Function MettreAjourBDDmobile()
var $dossier : 4D.Folder
var $fichier : 4D.File
var $data : Object
var $dateFichier4DD : Text
// initialiser le storage ; on doit avoir un dossier
$dossier:=cs._document.new().getBDDFolder()
If (Not($dossier.exists))
$dossier.create()
End if
// date du fichier de données actuel
$dateFichier4DD:=String(File(Data file; fk platform path).modificationDate; ISO date GMT)
// initialiser la mise à jour ; on doit avoir un fichier
$fichier:=$dossier.file("config.json")
If (Not($fichier.exists))
// créer le fichier
$data:=New object("dateFichier4DD"; $dateFichier4DD)
$fichier.setText(JSON Stringify($data; *))
End if
// ici on a toujours quelque chose
$data:=JSON Parse($fichier.getText())
Case of
: ($data=Null)
: (Not(OB Is defined($data; "dateFichier4DD")))
: ($data.dateFichier4DD=$dateFichier4DD)
// OK fichiers à jour
Else
// KO, mettre à jour les fichiers
This.CréerBDDmobile()
End case
// mettre à jour la BDD
This.ChargerBDDmobile()
Function CréerBDDmobile()
var $dataClassNom : Text
var $dossierTempo : 4D.Folder
var $fichier : 4D.File
$dossierTempo:=cs._Trace.me.cible.GetGarbageDossier().folder("tempo_WEBMO")
$dossierTempo.create()
For each ($dataClassNom; This.listeDataClass)
// créer le fichier
$fichier:=$dossierTempo.file($dataClassNom+".json")
This.CréerFichierBDDmobile($dataClassNom; $fichier)
// recopier dans le dossier serveurAPP
$fichier.copyTo(cs._document.new().getBDDFolder(); fk overwrite)
End for each
$dossierTempo.delete(Delete with contents)
Function CréerFichierBDDmobile($dataClassNom : Text; $fichier : 4D.File)
// créer la base de données locale sur disque local
var $c : Collection
var $dataClass; $selection : Object
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance"; Current method name; "Création du fichier de la DataClass "+$dataClassNom+" : "+$fichier.platformPath)
$dataClass:=cs[$dataClassNom].new().FixerParametresListe()
// créer la sélection d'entités (collection d'ID)
$selection:=cs[$dataClassNom+"Select"].new($dataClass.Requete)
// on a une sélection d'entités triées
$c:=$selection.CreerBDDmobile(This.tache)
// enregistrer
$fichier.setText(JSON Stringify($c))
// -----------------------------
// MARK:Medias
// -----------------------------
Function CréerMediaMobile()
var $sélection : cs.MediasSelect
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance Medias"; Current method name; "Démarrage du traitement Medias")
// récupérer la sélection de medias
$sélection:=cs.MediasSelect.new("private = 0 AND (type = 1 OR type = 2)")
$sélection.Créer()
// créer les fichiers pour Mobile
$sélection.CréerMediaMobile(This.tache)
// créer les vignettes pour Mobile
This.CréerVignettesMobile()
// créer les blasons
This.CréerBlasonsMobile()
// instaler le tout
cs._composant.new().InstallerRessourcesMEDIA(cs._document.new().getRacineHTMLFolder())
Function CréerVignettesMobile()
// stocker dans $folder les vignettes des media
var $dossierVignettes; $dossierMedias : 4D.Folder
var $file; $fichier : 4D.File
var $pict; $vignette : Picture
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance Medias"; Current method name; "Démarrage du traitement Vignettes")
$dossierMedias:=This.document.getMediasFolder()
$dossierVignettes:=This.document.getVignettesFolder()
For each ($file; $dossierMedias.files()) While (Not(This.tache.Tuer.signaled))
READ PICTURE FILE($file.platformPath; $pict)
// redimensionner l'image
CREATE THUMBNAIL($pict; $vignette; WebMob Icon largeur; WebMob Icon hauteur)
// passer en JPEG
CONVERT PICTURE($vignette; WebMob Icon format)
// enregistrer
$fichier:=$dossierVignettes.file(This.document.getVignetteNom(Num($file.fullName)))
WRITE PICTURE FILE($fichier.platformPath; $vignette; WebMob Icon format)
End for each
Function CréerBlasonsMobile()
var $sélection : cs.CommunesSelect
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Maintenance Medias"; Current method name; "Démarrage du traitement Blasons")
// récupérer la sélection de communnes
$sélection:=cs.CommunesSelect.new("ID > 0")
$sélection.Créer()
// créer les fichiers pour Mobile
$sélection.CréerBlasonsMobile(This.tache)
// -----------------------------
// MARK:Albums
// -----------------------------
Function InstallerAlbums()
var $DossierDestination : 4D.Folder
// ici le rootFolder est fixé : demander l'installation des albums
$DossierDestination:=This.document.getRacineHTMLFolder()
CALL WORKER("WK_Composant_WEBMO"; Formula(cs.xALB._maintenance.new().InstallerAlbums($DossierDestination)))
⇧
[class]EventsSelect - 04/10/2025 09:36:00
Class extends _WEBMO_DataStore
Class constructor($requête : Variant)
Super("EventsSelect"; $requête)
This.selection:=Null
Function LesProtagonistes()->$result : cs.PersonnesSelect
var $event : Object
var $c : Collection
$c:=New collection
For each ($event; This.selection)
$c:=$c.combine($event.LesProtagonistes().selection.extract("ID"))
End for each
// créer la liste
$result:=cs.PersonnesSelect.new($c)
Function LesMembres()->$result : Text
var $event : Object
var $c : Collection
$c:=New collection
For each ($event; This.selection)
$c:=$c.push($event.LesProtagonistes().selection.extract("nom").join("-"))
End for each
$c:=$c.distinct().orderBy(ck ascending)
// créer la liste
$result:=$c.join(", ")
Function EtatCivil()->$result : Text
// lister les events 'date' 'libellé protagonistes'
var $formats : Object
var $event : cs.Events
$result:=""
// on veut le symbole event, 'le'
$formats:=New object("Options"; 0x00109100; "FormatDate"; Internal date short; "FormatHeure"; HH MM)
For each ($event; This.selection)
$result+="<p>"+($event.FormaterDate($formats)+" "+$event.FormaterHeure($formats)+" "+$event.Libellé($formats))+"</p>"
End for each
⇧
[class]$authentificationEmail - 05/12/2025 19:18:58
property request; userInfo; resultActiverSession; resultEmailChecker : Object
property urlActiverSession : Text
Class extends _composant
Class constructor
Super()
This.request:=Null
This.userInfo:=Null
// url nécessitant un traitement
This.urlActiverSession:="activation"
This.resultActiverSession:=Null
Function getAdresseServeur()->$result : Text
$result:=cs.$serveur.new().getAdresseServeur()
Function getPortServeur()->$result : Text
var $serveur : 4D.WebServer
$serveur:=WEB Server(Web server database)
$result:=String($serveur.HTTPSPort)
// -----------------------------
// MARK:Authentification par eMail
// -----------------------------
Function Authentification($request : Object)->$response : Object
// traiter la demande d'authentification (équivalent de l'évènement 'On Mobile App Authentification')
// si ok, envoyer un eMail d'authentification
This.request:=$request
This.trace.EnvoyerMessages([msgk_log]; "$request :"; Current method name; JSON Stringify(OB Copy($request)))
$response:=New object("function"; Current method name; "success"; False)
Case of
: (Not(This.estUtilisateurIdentifié($request)))
// user inconnu
$response.statusText:=Localized string("7")
: (Not(This.FixerParamètresAuthentification()))
$response.statusText:="Erreur paramètres Authentification"
: (This.ConfirmerLogInParEmail())
$response:=This.resultEmailChecker
// initialiser les données de session
// ici un user a été identifié ; ses données sont dans This.userInfo
cs.$session.me.InitialiserSession()
Use (Session.storage)
Use (Session.storage.userInfo)
// info serveur
Session.storage.userInfo.eMail:=$request.email
Session.storage.userInfo.IDunique:=This.userInfo.IDunique
// info ALV
Session.storage.userInfo.userName:=This.userInfo.First_Name
Session.storage.userInfo.IDfamille:=This.userInfo.IDfamille
End use
End use
// initialiser le fichier session mobileWeb
cs.$session.me.setSessionFile($request.session.id; $request; Session.storage.userInfo)
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "$response :"; Current method name; "[OK] (voir détails $request et .userInfo dans Logs)")
This.trace.EnvoyerMessages([msgk_log]; "userInfo :"; Current method name; JSON Stringify(This.userInfo))
Else
This.trace.EnvoyerMessages([msgk_event]; "$response :"; Current method name; "Erreur construction / envoi de l'eMail")
End case
Function ConfirmerLogInParEmail()->$result : Boolean
// envoyer un eMail de confirmation
var $data : Object
This.resultEmailChecker:=cs.$session.me.WEBmobileEmailChecker(This.request)
$result:=This.resultEmailChecker.success
This.trace.EnvoyerMessages([msgk_event]; "resultEmailChecker"; Current method name; Choose($result; "[OK]"; "[KO]")+". Confirmation - message EmailChecker "+This.resultEmailChecker.statusText)
This.trace.EnvoyerMessages([msgk_log]; "resultEmailChecker"; Current method name; JSON Stringify(This.resultEmailChecker))
This.trace.EnvoyerMessages([msgk_log]; "sessionGetPrivileges"; Current method name; JSON Stringify(Session.getPrivileges()))
$data:=OB Copy(Session.storage)
OB REMOVE($data; "UserParams")
This.trace.EnvoyerMessages([msgk_log]; "sessionStorage"; Current method name; "isGuest() "+String(Session.isGuest())+" SessionStorage "+JSON Stringify($data))
Function FixerParamètresAuthentification()->$result : Boolean
// renseigner les infos du template utilisé par 'Mobile App Email Checker'
var $fichier; $params : Object
$fichier:=Folder(fk resources folder).folder("WEB mobile Server").file("settings.json")
If ($fichier.exists)
$params:=JSON Parse($fichier.getText())
Else
$params:=New object
End if
// renseigner les paramètres, objet .smtp (cf doc de Mobile App Email Checker)
// qui envoie le mail :
cs.xMAIL.$eMail.new().LireParametresSMTP($params)
This.rsc.SetObjet(Est ressource MAIL; "mail/authentificationUtilisateur"; Is text; $params.smtp; "from")
// le mail envoyé
$params.emailSubject:=This.cFct.LireLocatedSTR(2)
$params.template:=New object
$params.template.emailToSend:=This.CréerPageHTMLConfirmation()
// emailConfirmActivation : utilise la page par défaut (cf doc)
$params.activation:=New object
$params.activation.scheme:="https"
$params.activation.hostname:=This.getAdresseServeur()
$params.activation.port:=This.getPortServeur()
$params.activation.path:=This.urlActiverSession
// les messages utilisateur
$params.message:=New object
$params.message.successConfirmationMailMessage:=This.cFct.LireLocatedSTR(3) // "Verify your email address"
$params.message.waitSendMailConfirmationMessage:=This.cFct.LireLocatedSTR(6) // "The mail is already sent thank you to wait before sending again"
$params.message.successActiveSessionsMessage:=This.cFct.LireLocatedSTR(4) // "You are successfully authenticated"
$params.message.expireActiveSessionsMessage:=This.cFct.LireLocatedSTR(5) // "This email confirmation link has expired!"
// enregistrer
TEXT TO DOCUMENT($fichier.platformPath; JSON Stringify($params))
$result:=True
Function estUtilisateurIdentifié($data : Object)->$result : Boolean
// chercher le user
// normalement il n'y a qu'un user, si plusieurs on prend le premier
var $ID; $groupe : Integer
var $eMail; $LogIn; $Name; $First_Name; $UUID : Text
$result:=False
Case of
: ($data=Null)
: ($data.email="")
Else
// v9.5.4 : le login d'un user est son adresse Mail
$eMail:=$data.email
$ID:=-1
$LogIn:=""
$Name:=""
$First_Name:=""
$groupe:=-1
$UUID:=""
Begin SQL
SELECT ID, LogIn, Name, First_Name, Groupe, IDunique FROM UtilisateursALV WHERE Adresse_eMail = :$eMail INTO :$ID, :$LogIn, :$Name, :$First_Name, :$groupe, :$UUID;
End SQL
This.userInfo:=New object
If ($ID>0)
// on a trouvé quelqu'un
$result:=True
// ses infos de log
This.userInfo.LogIn:=$LogIn
This.userInfo.Name:=$Name
This.userInfo.First_Name:=$First_Name
This.userInfo.IDunique:=$UUID
This.userInfo.privileges:="ReadRecords"
// trouver son groupe familial
Begin SQL
SELECT IDfamille FROM wwwGroupes WHERE ID = :$groupe INTO :$ID;
End SQL
This.userInfo.IDfamille:=$ID
Else
This.userInfo.nom:="cher Inconnu"
End if
End case
Function CréerPageHTMLConfirmation()->$result : Text
// créer dans les ressources le contenu du eMail de confirmation d'authentification
// remarque : le template fournit par le composant 4D est en anglais et anonyme. Ici le texte est en français et personalisé
var $dataTexte : Text
var $dossier : Object
// chemin du template de la page
$dossier:=Folder(Get 4D folder(Current resources folder); fk platform path)
$result:="ConfirmMailTemplate.html"
// créer le document
$dataTexte:=Document to text($dossier.folder("TemplatesMobileWeb").file($result).platformPath; "UTF-8")
PROCESS 4D TAGS($dataTexte; $dataTexte; This.userInfo.prénom)
// enregistrer dans le serveur
$dossier:=Folder(Get 4D folder(Current resources folder; *); fk platform path)
TEXT TO DOCUMENT($dossier.folder("WEB mobile Server").file($result).platformPath; $dataTexte)
// -----------------------------
// MARK:Traitement des URL session
// -----------------------------
Function ActiverSession($url : Text)->$result : Boolean
// analyser l'URL envoyé depuis l'eMail
var $token : Text
var $data : Object
// ici on reçoit aussi les url Albums !
// requête refusée par défaut
$result:=False
If ($url=("@"+This.urlActiverSession+"@"))
// accepter la requête
This.resultActiverSession:=cs.$session.me.WebMobileActiveSession($url)
$result:=This.resultActiverSession.success
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Mobile Web Active Session"+Choose($result; " [OK]"; " [KO]"); Current method name; $url+" - message "+This.resultActiverSession.message+" - erreur "+This.resultActiverSession.error)
// lire l'ID
$token:=cs.$session.me.getTokenFromURL($url)
// lire user session
Case of
: (Not($result))
: (Not(OB Is defined(Session; "storage")))
: ($token="")
// *** bof
: (Not(OB Is empty(Session.storage.mobileWebInfo)))
// *** ré activation d'une session existante
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Session Active"; Current method name; "$token "+$token+" - isGuest() "+String(Session.isGuest())+" (voir détails dans logs)")
This.trace.EnvoyerMessages([msgk_log]; "Session Active"; Current method name; JSON Stringify(Session.storage))
Else
// *** nouvelle session
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Nouvelle Session"; Current method name; "$token "+$token)
// récupérer les infos de session mobileWeb
$data:=cs.$session.me.getSessionObjet($token)
cs.$session.me.InitialiserSessionInfos($data)
cs.$cookie.me.Ecrire("mobileWebID"; Session.id)
cs.$cookie.me.Ecrire("Expires"; "Thu, 01 Jan "+String(Year of(Current date)+2)+" 00:00:01 GMT")
End case
End if
⇧
[class]LieuxSelect - 04/10/2025 09:34:35
Class extends _WEBMO_DataStore
Class constructor($requête : Variant)
Super("LieuxSelect"; $requête)
This.selection:=Null
⇧
[class]$pageWebNAV - 30/10/2025 19:00:25
property prefixSelectionApp; prefixSelection; nomSelection : Text
property listeDataClass : Collection
Class extends $pageWeb
Class constructor()
Super()
This.prefixSelectionApp:="selectionNavAll"
This.prefixSelection:="selectionNav"
This.listeDataClass:=New collection("Personnes"; "Communes"; "Medias")
Function set NomSelectionNavAll($dataClassNom : Text)
This.nomSelection:=This.prefixSelectionApp+$dataClassNom
Function set NomSelectionNav($dataClassNom : Text)
This.nomSelection:=This.prefixSelection+$dataClassNom
// -----------------------------
// MARK:Création
// -----------------------------
Function CréerSelectionNavSession()
// créer les sélections All pour la session
var $dataClassNom : Text
Use (Session.storage.UserParams)
For each ($dataClassNom; This.listeDataClass)
This.NomSelectionNavAll:=$dataClassNom // attribut calculé
Session.storage.UserParams[This.nomSelection]:=New shared object
Use (Session.storage.UserParams[This.nomSelection])
// paramètrage des listes
Session.storage.UserParams[This.nomSelection].filtre:=""
Session.storage.UserParams[This.nomSelection].tri:=""
// selection d'entités
Session.storage.UserParams[This.nomSelection].selection:=New shared collection
sharedCollection(Storage.BDD[$dataClassNom]; Session.storage.UserParams[This.nomSelection].selection)
End use
End for each
End use
Function CréerListeHTML($selection : Collection; $params : Object)->$result : Text
var $texte : Text
$texte:=$selection.extract("Elementliste").join("")
PROCESS 4D TAGS($texte; $result; $params)
Function CréerSelectionNavAutre($dataClassNom : Text)
var $selection : Object
var $nomForm : Text
var $c : Collection:=[]
// créer la sélection à afficher
Case of
: ($dataClassNom="Medias")
$selection:=This.getCurrentEntityALL().LesMedias()
$nomForm:="mediaSimple"
: ($dataClassNom="Sites")
$selection:=This.getCurrentEntityALL().LesSites()
$nomForm:="detailSimple"
Else
$selection:=Null
End case
If (Not($selection=Null))
// créer la BDD de cette sélection à partir de la BDD
$c:=Storage.BDD[$dataClassNom].query("IDunique IN :1"; $selection.selection.extract("IDunique"))
// ajouter à session
This.NomSelectionNav:=$selection.DataClassNom
Use (Session.storage.UserParams)
Session.storage.UserParams[This.nomSelection]:=New shared object
End use
Use (Session.storage.UserParams[This.nomSelection])
Session.storage.UserParams[This.nomSelection].tri:=""
Session.storage.UserParams[This.nomSelection].selection:=New shared collection
End use
sharedCollection($c; Session.storage.UserParams[This.nomSelection].selection)
// récupérer et enregistrer les UUID
$c:=$selection.selection.extract("IDunique")
Use (Session.storage.UserParams[This.nomSelection])
Session.storage.UserParams[This.nomSelection].collection:=New shared collection
End use
sharedCollection($c; Session.storage.UserParams[This.nomSelection].collection)
End if
Function SelectionNavAllvide()->$result : Text
// créer une sélection vide, utilisées par défaut (par exemple si la maintenance n'a pas été lancée)
// il faut styler correctement le texte
$result:="<article id='0' class='element-listeEntity'>"
$result+=Localized string("1023")
$result+="</article>"
// -----------------------------
// MARK:Selection
// -----------------------------
Function getListeHTML()->$result : Text
var $data : Object
var $c : Collection
If (OB Is defined(Session.storage; "UserParams"))
If (Not(OB Is defined(Session.storage.UserParams; Session.storage.UserParams.currentSelectionNavNom)))
$result:=This.SelectionNavAllvide()
Else
$data:=OB Copy(Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom])
If ($data.tri="")
$c:=$data.selection
Else
$c:=$data.selection.orderBy($data.tri)
End if
$data:=cs[Session.storage.UserParams.EtatNavigation].new().FixerParametresListe()
$result:=This.CréerListeHTML($c; $data)
End if
End if
Function setSelectionNavAll($dataClassNom : Text)
// fixer le nom de la sélection pour la navigation dans l'App
This.NomSelectionNavAll:=$dataClassNom
// la stocker pour la navigation dans App et pour le retour d'une navigation annexe
Use (Session.storage.UserParams)
Session.storage.UserParams.Contexte:="ALL"
Session.storage.UserParams.currentSelectionNavNom:=This.nomSelection
Session.storage.UserParams.currentSelectionNavAllNom:=This.nomSelection
End use
Function setSelectionNavSelect($dataClassNom : Text)
// initialiser la navigation dans une sélection
This.CréerSelectionNavAutre($dataClassNom)
Use (Session.storage.UserParams)
Session.storage.UserParams.currentSelectionNavNom:=This.nomSelection
End use
Function setCurrentEntity($dataClassNom : Text; $UUID : Text)
// créer l'entité sélectionnée
var $entité : Object
$entité:=cs[$dataClassNom].new($UUID)
// la stocker
cs._CommunFunctions.me.AjouterObjetA($entité; Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom]; "currentEntity")
Function getCurrentEntity()->$result : Object
$result:=Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom].currentEntity
Function getCurrentEntityALL()->$result : Object
$result:=Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavAllNom].currentEntity
Function getNextEntityUUID()->$result : Text
var $c : Collection
var $index : Integer
$c:=Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom].collection
$result:=This.getCurrentEntity().IDunique
$index:=$c.indexOf($result)
If ($index<($c.length-1))
$result:=$c[$index+1]
End if
Function getPreviousEntityUUID()->$result : Text
var $c : Collection
var $index : Integer
$c:=Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom].collection
$result:=This.getCurrentEntity().IDunique
$index:=$c.indexOf($result)
If ($index>0)
$result:=$c[$index-1]
End if
// -----------------------------
// MARK:Actions
// -----------------------------
Function navGoToPrevious()
// navigation dans une page Detail
var $UUID; $url : Text
$UUID:=This.getPreviousEntityUUID()
$url:="/4DCGI/WebDATA/"+This.paramsUrl[0]+"?"+This.paramsUrl[1]+"?"+This.getCurrentEntity().DataClassNom+"?"+$UUID
WEB SEND HTTP REDIRECT($url)
Function navGoToNext($nomPage : Text)
// navigation dans une page Detail
var $UUID; $url : Text
$UUID:=This.getNextEntityUUID()
$url:="/4DCGI/WebDATA/"+This.paramsUrl[0]+"?"+This.paramsUrl[1]+"?"+This.getCurrentEntity().DataClassNom+"?"+$UUID
WEB SEND HTTP REDIRECT($url)
Function getFilterData()
// enregistrer la valeur du filtre et la collection d'entités résultante, calculés par l'agent
var $corps; $statusText : Text
var $data : Object
$statusText:="KO"
ARRAY TEXT($clésEntête; 0)
ARRAY TEXT($valeursEntête; 0)
WEB GET HTTP HEADER($clésEntête; $valeursEntête)
Case of
: (Not($valeursEntête{Find in array($clésEntête; "X-METHOD")}="POST"))
: (Not($valeursEntête{Find in array($clésEntête; "Content-Type")}="Application/alv-data"))
Else
WEB GET HTTP BODY($corps)
$data:=JSON Parse($corps)
Case of
: (Not(OB Is defined($data; "filtre")))
: (Not(OB Is defined($data; "collection")))
: (Session.storage.UserParams.currentSelectionNavNom="")
// pas initialisé (en debug par exemple)
Else
Use (Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom])
Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom].filtre:=$data.filtre
Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom].collection:=New shared collection
End use
sharedCollection($data.collection; Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom].collection)
$statusText:="OK"
End case
End case
WEB SEND TEXT($statusText)
// -----------------------------
// MARK:Navigation
// -----------------------------
Function Initialiser()
var $data : Object
// démarrage sur la page "Personnes"
$data:=Session.storage.UserParams
Use ($data)
$data.selectionNavMedias:=New shared object
$data.EtatNavigation:="Personnes"
End use
This.setSelectionNavAll("Personnes")
// initialiser les sélections User
This.CréerSelectionNavSession()
Function retourNavAll()
var $entité : Object
var $url : Text
$entité:=This.getCurrentEntityALL()
$url:="/4DCGI/WebDATA/AfficherFORMliste?detailSimple?"+$entité.DataClassNom+"?"+$entité.IDunique
WEB SEND HTTP REDIRECT($url)
Function retourNavSelect()
var $url : Text
$url:="/4DCGI/WebDATA/RafraichirFORMselection?collectionSelection?"+Session.storage.UserParams.EtatNavigation
WEB SEND HTTP REDIRECT($url)
Function retourNavExtension()
var $url : Text
$url:="/4DCGI/WebDATA/AfficherFORMdetail?detailSimple?"+Session.storage.UserParams.EtatNavigation+"?"+Session.storage.UserParams.UUIDretourNavigation
WEB SEND HTTP REDIRECT($url)
// wrapper (tout ce qui est extenstion est gérer par cs.$action
Function menuAfficherArbre()
cs.$action.new().menuAfficherArbre()
Function menuAfficherCarte()
cs.$action.new().menuAfficherCarte()
⇧
[class]$action - 08/02/2026 14:30:34
property carto : cs.xCarto.$carte
property entity : Object
Class extends $pageWeb
Class constructor()
Super()
This.carto:=cs.xCarto.$carte.new()
This.entity:=Null
Function TraiterURL($url : Text)->$result : Boolean
// traitement des url internes au serveur (appel des classes $pageXXX par les templates)
// remarque : dans cette version, ces url ont le même format que celles des requêtes client HTTP
$result:=False
This.result.nomMethode:=Current method name
// récupérer les paramètres
This.LireParametresUrl($url)
// normalement .balise[2] est le nom d'une function d'ici
Case of
: (This.balisesUrl=Null)
: (This.balisesUrl.length<3)
This.result.Error:=-15068
This.result.ErrorDescription:="url incorrecte - il manque la paramètres .balise[2]"
: (Not(OB Is defined(This; This.balisesUrl[2])))
This.result.Error:=-15068
This.result.ErrorDescription:="url incorrecte - .balise[2] '"+This.balisesUrl[2]+"' n'est pas une function de this "+OB Class(This).name
Else
// on accepte la demande
$result:=True
// le résultat, s'il y a, est dans this.result.resultat
// exécuter la function, en cas d'erreur elle peut renseigner This.result
This[This.balisesUrl[2]]()
End case
// -----------------------------
// MARK:Notes
// -----------------------------
// pour les notes, on utilise le woker pour générer du contenu HTML contextuel et, en particulier hors du composant ALB (qui ne reconnait pas les méthodes WEBMO ???)
Function AfficherNotes()
var $texte : Text
var $data : Object
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Création"; Current method name; "Notes de "+"?"+Session.storage.UserParams.EtatNavigation)
$texte:="<h2>"+Localized string("1108")+"</h2>"
// interroger la BDD_NOTE
$data:=New object("DataClassNom"; Session.storage.UserParams.EtatNavigation)
If (cs.$notes.new(New object).LireNotes($data))
$texte:=$data.notes
End if
// envoyer le contenu
WEB SEND TEXT(JSON Stringify([This.paramsUrl[0]; $texte]))
Function SaisirNote()
var $racineXML; $ElémentXML; $texte; $label : Text
This.InitStructureXML("article"; "")
//attention : la balise "textarea" ne doit pas être autofermante => il faut initialiser une valeur
// s'il existe une valeur, le placeholder ne fonctionne plus => supprimer la valeur après création du texte
$racineXML:=DOM Create XML element(This.RacineXML; "article"; "class"; "noteLibelle")
$ElémentXML:=DOM Create XML element($racineXML; "p")
DOM SET XML ELEMENT VALUE($ElémentXML; Localized string("218"))
$ElémentXML:=DOM Create XML element($racineXML; "article")
$ElémentXML:=DOM Create XML element($ElémentXML; "textarea"; "class"; "noteInput"; "id"; "noteObjet"; "name"; "noteObjet"; "placeholder"; "Une remarque, une correction..."; "type"; "text"; "value"; "")
DOM SET XML ELEMENT VALUE($ElémentXML; "toto")
// calculer la balise 219
Try
$label:=cs[Session.storage.UserParams.EtatNavigation].new().labelDataClass()
$label:=This.cFct.LireLocatedSTR(219; New object("param_1"; $label))
Catch
$label:=This.cFct.LireLocatedSTR(219; New object("param_1"; "L'ALBUM"))
End try
$racineXML:=DOM Create XML element(This.RacineXML; "article"; "class"; "noteLibelle")
$ElémentXML:=DOM Create XML element($racineXML; "p")
DOM SET XML ELEMENT VALUE($ElémentXML; $label)
$ElémentXML:=DOM Create XML element($racineXML; "article")
$ElémentXML:=DOM Create XML element($ElémentXML; "textarea"; "class"; "noteInput"; "id"; "noteContenu"; "name"; "noteContenu"; "placeholder"; "Description..."; "type"; "text"; "value"; "")
DOM SET XML ELEMENT VALUE($ElémentXML; "toto")
$texte:=This.ExporterStructureXML()
$texte:=Replace string($texte; "toto"; "")
// envoyer le contenu
WEB SEND TEXT($texte; "text/html")
Function AjouterNoteDeBDD()
// ajouter l'entité de BDD concernée
var $requete : Object
$requete:=JSON Parse(This.paramsUrl[0])
$requete.EntitéRéduite:=New object
$requete.EntitéRéduite.DataClassNom:=Session.storage.UserParams.EtatNavigation
$requete.EntitéRéduite.IDunique:=Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom].currentEntity.IDunique
This._AjouterNote($requete)
Function AjouterNoteDeALB()
// ajouter l'entité de l'image concernée
var $requete : Object
$requete:=JSON Parse(This.paramsUrl[0])
$requete.EntitéRéduite:=New object
$requete.EntitéRéduite.DataClassNom:=Session.storage.UserParams.EtatNavigation
$requete.EntitéRéduite.IDunique:=Session.storage.ALB_UserParams.Album.Medias[Num($requete.indexMedia)].MED_IDunique
This._AjouterNote($requete)
Function _AjouterNote($requete : Object)
// traiter la requete
var $response : Object
$requete.success:=False
Case of
: (Not(OB Is defined($requete; "EntitéRéduite")))
: (Not(OB Is defined($requete.EntitéRéduite; "DataClassNom")))
: (Not(OB Is defined($requete.EntitéRéduite; "IDunique")))
: (Not(OB Is defined($requete; "note")))
: (Not(OB Is defined($requete.note; "objet")))
: (Not(OB Is defined($requete.note; "contenu")))
Else
$requete.success:=True
cs.$notes.new($requete).EcrireNote()
End case
$response:=New object
$response.success:=$requete.success
$response.message:=Localized string(String(1020+Num($response.success)))
WEB SEND TEXT(JSON Stringify($response))
// -----------------------------
// MARK:Arbre
// -----------------------------
Function menuAfficherArbre()
// ouvrir l'arbre
cs.$serveur.new().InitSession("ARB")
// renseigner deQui
Use (Session.storage.UserParams)
// par defaut la personne sélectionnée
Session.storage.UserParams.UUIDretourNavigation:=Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom].currentEntity.IDunique
// voir si on a cliquer sur un lien d'arbre
Case of
: (Not(OB Is defined(This; "paramsUrl")))
: (This.paramsUrl.length<2)
Else
// utiliser cette personne
Session.storage.UserParams.UUIDretourNavigation:=This.paramsUrl[1]
End case
End use
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Initialisation"; Current method name; "Arbre de ?Personnes?"+String(Session.storage.ARB_HTTPvars.UUIDpersonne))
This.Envoyer("mobileArbreAfficher.shtml"; "Personnes"; "ARB_HTTPvars")
Function AfficherArbre()
// une page Web est affichée et en attente de contenu
// créer l'arbre de Session.storage.UserParams.ARB_IDdeCujus
var $params; $EtatProcessus : Object
var $arbreXML; $RacineXML; $texte : Text
var $ID : Integer
// message en cas d'erreur
$texte:="<h2>"+This.cFct.LireLocatedSTR(11)+"</h2>"
Case of
: (Not(OB Is defined(Session.storage.UserParams; "UUIDretourNavigation")))
Else
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Création"; Current method name; "Arbre de "+"?Personnes?"+Session.storage.UserParams.UUIDretourNavigation)
// c'est ok
$ID:=cs.Personnes.new(Session.storage.UserParams.UUIDretourNavigation).ID
OB SET($params; "IDarbre"; $ID)
OB SET($params; "IDpersonne"; CodeEnreg($ID; [1]))
OB SET($params; "NmaxAscendance"; 3)
OB SET($params; "NmaxDescendance"; 1)
OB SET($params; "CheminDossierBDD_AG"; This.document.getSessionFolder().platformPath)
OB SET($params; "nomBDD"; "ARB")
OB SET($params; "Modele"; "MobileArbre.xml")
OB SET($params; "functionID"; "Construire_AG")
OB SET($params; "Session_Etat"; Storage.Host.Session_Etat)
OB SET($params; "optionsMsg"; [msgk_event])
// options : on veut les cadres des personnes absentes (=> largeur image SVG fixe)
OB SET($params; "Options"; 0x0023) // liens dynamiques
OB SET($params; "SéparateurParamsURL"; "?") // séparateur des paramètres dans les URL (4DACTION...)
// initialiser l'état
OB SET($EtatProcessus; "Params"; 0x0000)
//OB FIXER($EtatProcessus;"Params";0x0000 ?? 25) // afficher viewer
OB SET($EtatProcessus; "SaisieAutorisée"; False)
OB SET($params; "EtatProcessus"; $EtatProcessus)
// on lance (le résultat sera reçu dans arbreXML)
cs.xARB.$arbre.new().Imager_AG($params)
If ($params.arbreXML#"")
$arbreXML:=$params.arbreXML
// récupérer l'arbre
$RacineXML:=DOM Parse XML variable($arbreXML)
DOM EXPORT TO VAR($RacineXML; $texte)
// pour des tests
//DOM EXPORTER VERS FICHIER($RacineXML; Dossier 4D(Dossier Logs; *)+"Test Arbre.xml")
DOM CLOSE XML($RacineXML)
// supprimer la balise <?xml >
$texte:=Substring($texte; Position("<"; $texte; 2; *))
Else
$texte:=JSON Stringify($params.EtatProcessus; *)
End if
End case
// envoyer le contenu
WEB SEND TEXT($texte)
// -----------------------------
// MARK:Carte
// -----------------------------
Function menuAfficherCarte()
// ouvrir la carte
// variables process d'ici
var wwwCarto_Opacity_OSM; wwwCarto_Opacity_GP; wwwCarto_Opacity_Cible; wwwZoneWeb_ZoomMin; wwwZoneWeb_ZoomMax : Text
var wwwCarto_Install_GP : Text
// variables fixées par le composant CARTO
var wwwCarto_LatitudeCentre; wwwCarto_LongitudeCentre; wwwZoneWeb_Zoom; ZoneWeb_Largeur; ZoneWeb_Hauteur; wwwMediaPath : Text
This.entity:=Session.storage.UserParams[Session.storage.UserParams.currentSelectionNavNom].currentEntity
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Initialisation"; Current method name; "Carte de "+"?"+This.entity.DataClassNom+"?"+This.entity.IDunique)
vs4D:=""
cs.$serveur.new().InitSession("CARTO")
wwwCarto_LatitudeCentre:=""
wwwCarto_LongitudeCentre:=""
wwwZoneWeb_Zoom:=""
ZoneWeb_Largeur:=""
ZoneWeb_Hauteur:=""
wwwMediaPath:=""
// renseigner deQui
// l'entité sélectionnée
Use (Session.storage.UserParams)
Session.storage.UserParams.UUIDretourNavigation:=This.entity.IDunique
End use
Use (Session.storage.CARTO_HTTPvars)
// nécessaires pour .getCarteData()
Session.storage.CARTO_HTTPvars.wwwRacineRessources:="../../"
Session.storage.CARTO_HTTPvars.wwwContexteWeb:="ALVmobile"
// initialiser les variables process contenus dans la carte
Session.storage.CARTO_HTTPvars.wwwCarto_Install_GP:="false"
Session.storage.CARTO_HTTPvars.wwwCarto_Opacity_Cible:="0.0"
This.rsc.SetObjet(Est Ressource WEBMO; "Carte/Carto_Opacity_OSM"; Is text; Session.storage.CARTO_HTTPvars; "wwwCarto_Opacity_OSM")
This.rsc.SetObjet(Est Ressource WEBMO; "Carte/Carto_Opacity_GP"; Is text; Session.storage.CARTO_HTTPvars; "wwwCarto_Opacity_GP")
// zoom
This.rsc.SetObjet(Est Ressource WEBMO; "Carte/Carto_ZoomMin_OL"; Is text; Session.storage.CARTO_HTTPvars; "wwwZoneWeb_ZoomMin")
This.rsc.SetObjet(Est Ressource WEBMO; "Carte/Carto_ZoomMax_OL"; Is text; Session.storage.CARTO_HTTPvars; "wwwZoneWeb_ZoomMax")
End use
// créer les data de la carte
This.AfficherCarte()
// envoyer la page
This.Envoyer(Choose(OB Is defined(Session.storage.CARTO_HTTPvars; "wwwCarto_LatitudeCentre"); "mobileCarteAfficher.shtml"; "mobileCarteVide.shtml"); Session.storage.UserParams.EtatNavigation; "CARTO_HTTPvars")
Function AfficherCarte()
// créer les données de la carte
var $params : Object
This.trace.EnvoyerMessages([msgk_event; msgk_log]; "Création"; Current method name; "Carte de "+"?"+This.entity.DataClassNom+"?"+This.entity.IDunique)
// init de la sélection de lieux et des paramètres associés de la zone à afficher
$params:=New object
// récepteur des variables process
$params.HTTPvars:=OB Copy(Session.storage.CARTO_HTTPvars)
// l'entité à cartographier (entité réduite , ici pas de DataStore)
$params.sélection:=New collection(New object("DataClassNom"; This.entity.DataClassNom; "IDs"; New collection(This.entity.ID)))
// créer le dossier où mettre les fichiers
$params.cheminRacineHTML:=This.document.getRacineHTMLFolder().platformPath
// dossier de sessions
$params.SessionID:=Session.id
$params.cheminSessionFolder:=This.document.getSessionFolder().platformPath
$params.sousDossierImages:="images"
// urls sur le serveur Web
$params.nomFichierMarkers:="dataGP_"+This.entity.IDunique+".js"
// pour la page Web, icones d'instance vues au niveau de la session
$params.dossierCartoURL:=$params.HTTPvars.wwwRacineRessources+Localized string("129")+"/"+Session.id
// formats pour mobile
$params.Apparence:=New object("CodeLangue"; "fr"; "SymbolConjoints"; " & "; "SymbolDateLieu"; " - "; "FormatDate"; 5; "FormatHeure"; 2; "FormatLieu"; 1; "FormatGeoLoc"; 1)
$params.PopUpOptions:=New object("Lieux"; 0x00040000; "Communes"; 0x00C80000; "Departements"; 0x00C80000; "Regions"; 0x00880000; "Pays"; 0x0000)
$params.PopUpLiens:=True
// demander la carte et générer ses données de session
This.carto.getCarteData($params)
// installer les ressources carto
This.carto.InstallerRessources($params.cheminRacineHTML)
// créer les fichiers
This.carto.InstallerDonnées($params)
// récupérer les MarkersData
Use (Session.storage.CARTO_Data)
Session.storage.CARTO_Data.MarkersData:=$params.data.MarkersData
End use
// récupérer les variables process
sharedObject($params.HTTPvars; Session.storage.CARTO_HTTPvars)
// -----------------------------
// MARK:Album
// -----------------------------
Function AfficherMediaALB()
// bouchonner l'appel
var $texte : Text
$texte:=JSON Stringify({vide: "vide"}; *)
// envoyer le contenu
WEB SEND TEXT($texte)
⇧
[class]_Trace - 15/11/2025 16:09:14
property cible : cs.xSDK.Traces
property success : Boolean
property origine : Text
singleton Class constructor()
This.cible:=cs.xSDK.Traces.new()
This.success:=False
This.origine:="WEBMO"
// ----------------------
//MARK:Wrappers
// ----------------------
Function set Error($numError : Integer)
This.cible.Error:=$numError
Function get Error()->$result : Integer
$result:=This.cible.Error
Function set ErrorDescription($description : Text)
This.cible.ErrorDescription:=$description
Function get ErrorDescription()->$result : Text
$result:=This.cible.ErrorDescription
Function Intercepter()
ErrorNum:=This.cible.Intercepter(This.origine; Error; Error method; Error line; Error formula)
Function Initialiser($nomMethode : Text)->$result : Object
This.cible.CréerErreur(This.origine; 0; $nomMethode; "")
$result:=This
Function Créer($Error : Integer; $nomMethode : Text; $ErrorDescription : Text)->$result : Object
This.cible.CréerErreur(This.origine; $Error; $nomMethode; $ErrorDescription)
$result:=This
Function FixerSuccess()
This.cible.FixerSuccess()
This.success:=This.cible.success
Function LeverException($options : Collection)
// renseigner le label de l'erreur
This.cible.ErrorLabel:=Localized string(String(This.cible.Error))
// lancer le traitement de l'erreur
This.cible.LeverException($options)
Function EnvoyerMessages($options : Collection; $libellé : Text; $source : Text; $description : Text)
This.cible.EnvoyerMessages($options; This.origine; $libellé; $source; $description)
Function DebugerMethode($libellé : Text; $source : Text; $description : Text)->$result : Boolean
// mettre à jour l'état (activation / désactivation des ASSERT)
cs._composant.new().InstallerDonnéesHote()
$result:=This.cible.DebugerMethode(Storage.Host; This.origine; $libellé; $source; $description)
Function DebugerVariables($libellé : Text; $source : Text; $data : Object)->$result : Boolean
// toujours appelé par un ASSERT (Storage.Host ne peut être réactualisé)
$result:=This.cible.DebugerVariables(Storage.Host; This.origine; $libellé; $source; $data)
// ----------------------
//MARK:Session
// ----------------------
Function Session($nomMethode : Text; $url : Text)
var $data : Object
var $c : Collection
var $attribut : Text
$data:=New object
$data.methode:=$nomMethode
$data.url:=$url
$data.numProc:=Current process
$data.nomProc:=Current process name
$data.storage:=Null
Case of
: (Not(Get assert enabled))
: (Session=Null)
$data.id:="pas de session ouverte"
Else
$data.id:=Session.id
$data.userName:=Session.userName
$data.isGuest:=Session.isGuest()
$data.idleTimeout:=Session.idleTimeout
$data.expirationDate:=Session.expirationDate
$data.HTTPvars:=Null
If (OB Is defined(Session.storage; "HTTPvars"))
$data.HTTPvars:=OB Copy(Session.storage.HTTPvars)
End if
// les variables process courantes
$c:=OB Keys(Session.storage.HTTPvars)
$data.HTTPvarsCourantes:=New object
For each ($attribut; $c)
$data.HTTPvarsCourantes[$attribut]:=Get pointer($attribut)->
End for each
$data.UserParams:=Null
If (OB Is defined(Session.storage; "UserParams"))
$data.UserParams:=OB Copy(Session.storage.UserParams)
End if
// pour finir
//$data.storage:=OB Copier(Session.storage)
End case
ASSERT(cs._Trace.me.DebugerVariables(String(Milliseconds)+"_SessionStorage"; Current method name; $data)) // "Options"; 0x0080
⇧
[class]Personnes - 30/10/2025 18:17:52
property lesEvents : cs.EventsSelect
// attributs de la classe
property nom; prenom; autres_prenoms; metier; commentaire : Text
property sexe : Boolean
Class extends _WEBMO_DataStore
Class constructor($IDentité : Variant)
Super("Personnes"; $IDentité)
This.lesEvents:=Null
Function FixerParametresListe()->$result : Object
$result:=New object
$result.DataClassNom:="Personnes"
$result.Requete:="id>0"
$result.nomFunction:="AfficherFORMdetail"
$result.nomFORMlist:="detailSimple"
$result.TriParNom:="nom asc, prenom asc"
$result.TriParPrenom:="prenom asc, nom asc"
Function CreerBDDentity()->$result : Object
$result:=New object
$result.IDunique:=This.IDunique
$result.nom:=This.nom
$result.prenom:=This.prenom
$result.Elementliste:=This.Elementliste()
// les champs calculés
Super.CreerBDDentity($result; ["Champ_1"; "Champ_2"; "Champ_3"; "Champ_4"; "Champ_boutonLibelle_1"; "Champ_boutonLibelle_2"; "Champ_titreIconed_1"; "Champ_titreIconed_2"])
Function labelDataClass()->$result : Text
$result:=Super.labelDataClass("la ")
Function RédigerCommentaire($formats : Object)->$result : Text
var $c : Collection
$result:=""
$c:=New collection
Case of
: (Not($formats.params ?? 0))
: (Not(OB Is defined($formats; "séparateurComments")))
: (Not(OB Is defined($formats; "débutComment")))
: (Not(OB Is defined($formats; "finComment")))
Else
$c.push(This.metier; This.commentaire)
$result:=$c.join($formats.séparateurComments; ck ignore null or empty)
End case
$result:=($formats.débutComment+$result+$formats.finComment)*Num(Length($result)#0)
// ----------------------
//MARK:Sélection
// ----------------------
Function Naissance()->$result : Object
// renvoie un objet _EvenementPersonnel
$result:=This.EvenementPersonnel(22000)
Function Baptême()->$result : Object
// renvoie un objet _EvenementPersonnel
$result:=This.EvenementPersonnel(22300)
Function Décès()->$result : Object
// renvoie un objet _EvenementPersonnel
$result:=This.EvenementPersonnel(22100)
Function EvenementPersonnel($type : Integer)->$result : Object
// renvoie l'entité events perso de type $1
var $c : Collection
If (This.lesEvents=Null)
This.cFct.AjouterObjetA(This.LesEvents(); This; "lesEvents")
End if
$result:=Null
$c:=This.lesEvents.selection.query("type = :1"; $type)
If ($c.length>0)
$result:=$c[0]
End if
Function LesMediasPerso()->$result : cs.MediasSelect
// créer la collection des medias perso (type = 1)
$result:=cs.MediasSelect.new(This.dataClass.LesMediasDeTypeZone(1))
$result.Créer()
Function LesMedias()->$result : cs.MediasSelect
// créer la collection de tous les medias où apparait this
$result:=cs.MediasSelect.new(This.dataClass.LesMediasDeTypeZone(-1))
$result.Créer()
// supprimer les flux et les medias privées, et trier par date
$result.selection:=$result.selection.query("type != :1 AND private = 0"; 3).orderBy("dateNum asc")
// attention, les liens généalogiques (Parents et conjoint) ne peuvent pas être traités ici en direct
// la création des personnes ramènerait ici, d'où un bouclage infernale
// Parents et conjoints sont accessibles par les fonctions suivantes
Function LesEvents()->$result : cs.EventsSelect
// créer la collection des events
$result:=cs.EventsSelect.new(This.dataClass.LesEvents())
$result.Créer()
Function LesUnions()->$result : cs.UnionsSelect
// créer la collection des unions triées par date
$result:=cs.UnionsSelect.new(This.dataClass.LesUnions())
$result.Créer()
// trier les unions par date
$result.selection:=$result.selection.orderBy("leEvent.dateNum asc")
// ----------------------
//MARK: FORM Liste
// ----------------------
Function Elementliste()->$result : Text
$result+="<article id='"+This.IDunique+"' class='element-listeEntity' nom='"+This.nom+"' prenom='"+This.prenom+"'>"
$result+="<article>"
$result+=This.LibelléLié(This._tagUrl+"WebDATA/<!--#4DEVAL $1.nomFunction-->?<!--#4DEVAL $1.nomFORMlist-->?Personnes?"+This.IDunique; New object("Options"; 3))
$result+="</article>"
$result+="<article><span>"
$result+=This.DatesDeVie()
$result+="</span></article>"
$result+="</article>"
Function DatesDeVie()->$result : Text
var $naissance; $décès : Object
$naissance:=This.Naissance()
Case of
: ($naissance=Null)
: ($naissance.dateChaine="")
Else
// on a une date, pas forcément valide
$result:=$naissance.dateChaine
End case
$result:=$result+" - "
$décès:=This.Décès()
Case of
: ($décès=Null)
: ($décès.dateChaine="")
Else
// on a une date, pas forcément valide
$result:=$result+$décès.dateChaine
End case
// ----------------------
//MARK: FORM Detail
// ----------------------
Function Champ_1()->$result : Text
// photo d'identité
var $selection : Object
$selection:=This.LesMediasPerso()
Case of
: ($selection.selection.length>0)
$selection.selection:=$selection.selection.orderBy("dateNum desc")
$result:=$selection.selection[0].getVignetteUrl($selection.selection[0].ID)
: (This.sexe)
// icone femelle
$result:="../../ressources/Images/16811.png"
Else
// icone male
$result:="../../ressources/Images/16812.png"
End case
Function Champ_2()->$result : Text
$result:=This.nom
Function Champ_3()->$result : Text
$result:=This.prenom+" "+This.autres_prenoms
Function Champ_4()->$result : Text
var $data : Object
OB SET($data; "params"; 0x000D)
This.cFct.AjouterObjetA(This; $data; "entité")
$result:=This.InformationEntité($data)
Function Champ_boutonLibelle_1()->$result : Text
$result:="16829.svg"
Function Champ_boutonLibelle_2()->$result : Text
$result:=Localized string("145")
Function Champ_titreIconed_1()->$result : Text
$result:="16830.svg"
Function Champ_titreIconed_2()->$result : Text
$result:=Localized string("146")
Function NomComplet()->$result : Text
Case of
: ((This.nom=Null) & (This.prenom=Null))
$result:="Inconnu"
: (This.nom=Null)
$result:=This.prenom
: (This.prenom=Null)
$result:=This.nom
Else
$result:=This.nom+" "+This.prenom
End case
⇧
[class]UnionsSelect - 04/10/2025 09:34:53
Class extends _WEBMO_DataStore
Class constructor($requête : Variant)
Super("UnionsSelect"; $requête)
This.selection:=Null
This.length:=0
⇧
[class]Events - 04/10/2025 09:35:41
// attributs de la classe
property heure : Time
property dateNumValid : Boolean
//property dateNum : Date
property dateChaine; commentaire : Text
//property genre : Boolean
Class extends _WEBMO_DataStore
Class constructor($IDentité : Variant)
// initialiser l'objet avec les données de l'entité $IDentité de la BDD
// rappel : l'event est genré dynamiquement (voir le getEvent() de la classe Personne)
Super("Events"; $IDentité)
Function RédigerCommentaire($formats : Object)->$result : Text
$result:=""
Case of
: (Not($formats.params ?? 0))
: (Not(OB Is defined($formats; "débutComment")))
: (Not(OB Is defined($formats; "finComment")))
Else
$result:=This.commentaire
End case
$result:=($formats.débutComment+$result+$formats.finComment)*Num(Length($result)#0)
// ----------------------
//MARK:Wrappers
// ----------------------
Function Libellé($userFormats : Object)->$libellé : Text
var $formats : Object
// on va les modifier
$formats:=OB Copy($userFormats)
// ajouter les formats manquants
This._FixerParamètresLibellé($formats)
$libellé:=This.dataClass.Libellé($formats)
// ----------------------
//MARK:Selection
// ----------------------
Function LesProtagonistes()->$result : cs.PersonnesSelect
$result:=cs.PersonnesSelect.new(This.dataClass.LesProtagonistes())
$result.Créer()
// ----------------------
//MARK:Form Detail
// ----------------------
Function FormaterDate($formats : Object)->$result : Text
// code dateNum dans le format $Formats avec les options $3.Options
// $formats :
// .FormatDate
// .FormatHeure
// .Options:
//. bit 8 = entête
var $data : Object
var $options : Integer
$result:=""
$options:=$Formats.Options
$data:=New object("dateChaine"; This.dateChaine)
cs.xSDK.Outils.me.getDateNum($data)
// mettre au format demandé
Case of
: ($Formats.FormatDate=0) // la date de la BDD au format numérique
$formats.dateValide:=$data.dateNumValid
$formats.dateNum:=Add to date(!00-00-00!; Year of($data.dateNum); Month of($data.dateNum); Day of($data.dateNum))
: ($Formats.FormatDate=Internal date long) // la date mémorisée en la BDD
$result:=Choose(($options ?? 8) & $data.dateNumValid; Localized string("1008"); " ")+This.dateChaine
: ($Formats.FormatDate=Internal date short) // la date de la BDD si possible au format numérique 7 = "jj-mm-aaaa"
Case of
: ($data.dateNumValid)
$result:=(Localized string("1008")*Num($options ?? 8))+String(Day of($data.dateNum))+"-"+String(Month of($data.dateNum))+"-"+String(Year of($data.dateNum))
: (This.dateChaine="")
$result:=This.cFct.LireLocatedSTR(1004) // inconnu
Else
$result:=(" "*Num($options ?? 8))+This.dateChaine
End case
: ($Formats.FormatDate=11) // la date de la BDD au format numérique = "aaaa"
$result:=String(Year of($data.dateNum))
End case
Function FormaterHeure($formats : Object)->$result : Text
// code heure dans le format $Formats avec les options $3.Options
// $formats :
// .FormatHeure
// .Options:
// bit 8 = entête
var $options : Integer
var $texte : Text
$options:=$Formats.Options
$texte:=String(Time(This.heure); Num($Formats.FormatHeure))
$texte:=Replace string($texte; ":"; "h"; *)
$texte:=(Localized string("33")*Num($options ?? 8))+$texte
$result:=$texte*Num(Not(Time(This.heure)=?00:00:00?))
⇧
[class]PersonnesSelect - 04/06/2026 14:22:46
Class extends _WEBMO_DataStore
Class constructor($requête : Variant)
Super("PersonnesSelect"; $requête)
This.selection:=Null
This.length:=0
Function LesPatronymes()->$result : cs.DicoDesNomsSelect
$result:=cs.DicoDesNomsSelect.new(This.dataClass.LesPatronymes())
// ----------------------
//MARK:PageHTML
// ----------------------
Function CreerBDDmobile($tâche : cs.xSDK.Tache)->$result : Collection
var $entité : cs.Personnes
// créer la sélection d'entités
This.Créer()
// créer les entités de la BDD mobile
$result:=New collection
If (This.selection.length>0)
// ordonner
This.selection:=This.selection.orderBy("nom asc, prenom asc")
For each ($entité; This.selection) While (Not($tâche.Tuer.signaled))
$result.push($entité.CreerBDDentity())
End for each
End if
⇧
[class]Medias - 30/11/2025 10:58:14
property fct : cs.xSDK.Outils
property lesPersonnages : Object
property lesInstantanes; lesPaysages : Collection
// attributs de la classe
property nom; dateChaine; titre; commentaire; nomFichier : Text
property type : Integer
property dateNum : Date
Class extends _WEBMO_DataStore
Class constructor($IDentité : Variant)
Super("Medias"; $IDentité)
This.fct:=cs.xSDK.Outils.me
Function FixerParametresListe()->$result : Object
$result:=New object
$result.DataClassNom:="Medias"
$result.Requete:="private = 0 AND (type = 1 OR type = 2)"
$result.nomFunction:="AfficherFORMdetail"
$result.nomFORMlist:="mediaSimple"
$result.TriParTitre:="titre asc, dateNum asc"
$result.TriParDate:="dateNum asc, titre asc"
Function CreerBDDentity()->$result : Object
$result:=New object
$result.IDunique:=This.IDunique
$result.dateNum:=This.dateNum
$result.titre:=This.titre
$result.Elementliste:=This.Elementliste()
// les champs calculés
Super.CreerBDDentity($result; ["Champ_1"; "Champ_2"; "Champ_3"; "Champ_ParagrapheTitre_11"; "Champ_ParagrapheTitre_12"; "Champ_ParagrapheTitre_21"; "Champ_ParagrapheTitre_22"])
Function labelDataClass()->$result : Text
$result:=Super.labelDataClass("le ")
// ----------------------
//MARK:Sélection
// ----------------------
Function getLesLiens()
This._LesPersonnages()
This._LesInstantanes()
This._LesPaysages()
Function _LesPersonnages()
var $selection : cs.PersonnesSelect
$selection:=cs.PersonnesSelect.new(This.dataClass.LesPersonnes())
// créer .selection
$selection.Créer()
Use (This)
This.lesPersonnages:=New shared object
End use
This.cFct.AjouterObjetA($selection; This; "lesPersonnages")
Function _LesInstantanes()
var $selection : Object
$selection:=cs.EventsSelect.new(This.dataClass.LesEvents())
// créer .selection
$selection.Créer()
Use (This)
This.lesInstantanes:=New shared collection
End use
This.cFct.AjouterObjetA($selection; This; "lesInstantanes")
Function _LesPaysages()
var $selection : Object
$selection:=cs.EventsSelect.new(This.dataClass.LesLieux())
// créer .selection
$selection.Créer()
Use (This)
This.lesPaysages:=New shared collection
End use
This.cFct.AjouterObjetA($selection; This; "lesPaysages")
// ----------------------
//MARK: FORM Liste
// ----------------------
Function Elementliste()->$result : Text
$result:="<article id='"+This.IDunique+"' class='element-collection' nom='"+This.titre+"' date='"+String(This.dateNum)+"'>"
$result+=This.ImageLié()
$result+="<article class='date-Collection'><span>"
$result+=This.dateChaine
$result+="</span></article>"
$result+="<article class='titre-Collection'><span>"
$result+=This.titre
$result+="</span></article>"
$result+="</article>"
Function ImageLié()->$result : Text
$result:="<a href="+Char(Double quote)
$result+=This._tagUrl+"WebDATA/<!--#4DEVAL $1.nomFunction-->?<!--#4DEVAL $1.nomFORMlist-->?Medias?"+This.IDunique
$result+=Char(Double quote)+"><img class="+Char(Double quote)+"image-Collection"+Char(Double quote)+" src="
$result+=This.getVignetteUrl(This.ID)
$result+=" alt="+Char(Double quote)+String(This.ID)+Char(Double quote)+"/></a>"
// ----------------------
//MARK: FORM Detail
// ----------------------
Function getVignetteUrl($ID : Integer)->$result : Text
$result:=This.document.getVignetteURL($ID)
Function Champ_1()->$result : Text
$result:="<img src="
$result+=This.getMediasURL()
$result+=" alt="+Char(Double quote)+String(This.ID)+Char(Double quote)+"</>"
//Function Champ_1New()->$result : Text
//Case of
//: (This.type=1)
//$result:="<img src="
//$result+=This.getMediasURL()
//$result+=" alt="+Char(Double quote)+String(This.ID)+Char(Double quote)+"</>"
//: (This.type=2)
//$result:="<embed type='application/pdf' src="
//$result+=This.getMediasURL()
//$result+=" alt="+Char(Double quote)+String(This.ID)+Char(Double quote)+"</>"
//End case
Function Champ_2()->$result : Text
$result:=This.dateChaine
Function Champ_3()->$result : Text
$result:=This.titre
Function Champ_ParagrapheTitre_11()->$result : Text
$result:=Localized string("153")
Function Champ_ParagrapheTitre_12()->$result : Text
// décrire les zones accrochées à this
var $entité : Object
var $texte : Text
This.getLesLiens()
Case of
: (This.lesInstantanes.selection.length=1)
// lié à un event
$texte:=This.lesInstantanes.selection[0].Libellé(New object("Options"; 0x0103DD00))
$result:="Photo prise lors "+$texte
: (This.lesPaysages.selection.length=1)
// un lieu
$texte:=This.lesPaysages.selection[0].Libellé(New object("Options"; 0x00CA0000))
$result:="Photo prise à "+$texte
End case
// récupérer les zones personnages
If (This.lesPersonnages.selection.length>0)
// attention : éviter de mettre le bazar dans les sélections utilisées
// ici, on n'utilise pas les liens pour remonter aux personnes ; cela perturbe les autres fonctions (tri par la date en particulier)
$texte:=""
For each ($entité; This.lesPersonnages.selection)
$texte+=", "+$entité.Libellé(New object("Options"; 0x0003))
End for each
// nettoyer
$texte:=Substring($texte; 3)
$texte:=Choose(This.lesPersonnages.selection.length=1; "Personne présente : "; "Personnes présentes (de gauche à droite) : ")+$texte
$result+=(". "*Num(Length($result)>0))+$texte
End if
Function Champ_ParagrapheTitre_21()->$result : Text
$result:=Localized string("151")
Function Champ_ParagrapheTitre_22()->$result : Text
$result:=This.commentaire
// -----------------------------
// MARK:Maintenance
// -----------------------------
Function getMediaNom()->$result : Text
$result:="media_"+String(This.ID; "00000")+WebMob Image format
Function getMediaNomNew()->$result : Text
Case of
: (This.type=1)
$result:="media_"+String(This.ID; "00000")+WebMob Image format
: (This.type=2)
$result:="media_"+This.nomFichier
End case
Function getMediasURL()->$result : Text
If (Storage.System.estExécutéDansHôte)
$result:=This.document.getDataURL()
Else
$result:="../../ressources/Images/mobileData/"
End if
$result+=Localized string("147")+"/"+This.getMediaNom()
⇧
[class]CommunesSelect - 04/06/2026 12:56:14
Class extends _WEBMO_DataStore
Class constructor($requête : Variant)
Super("CommunesSelect"; $requête)
This.selection:=Null
This.length:=0
// ----------------------
//MARK:PageHTML
// ----------------------
Function CreerBDDmobile($tâche : cs.xSDK.Tache)->$result : Collection
var $entité : cs.Communes
// créer la sélection d'entités
This.Créer()
// créer les entités de la BDD mobile
$result:=New collection
If (This.selection.length>0)
// ordonner
This.selection:=This.selection.orderBy("nom asc")
For each ($entité; This.selection) While (Not($tâche.Tuer.signaled))
$result.push($entité.CreerBDDentity())
End for each
End if
// -----------------------------
// MARK:Maintenance
// -----------------------------s
Function CréerBlasonsMobile($tâche : cs.xSDK.Tache)
var $dossier : 4D.Folder
var $entité : cs.Communes
$dossier:=This.document.getBlasonsFolder()
For each ($entité; This.selection) While (Not($tâche.Tuer.signaled))
$entité.CréerBlasonMobile($dossier)
End for each
⇧
[class]$cookie - 05/12/2025 19:19:02
property liste : Collection
singleton Class constructor()
// -----------------------------
// MARK:Traitement des cookies
// -----------------------------
Function Lire()->$result : Collection
// lire le contenu du cookie
// rappel : de base 4D crée un cookie avec le nom "4DSID_ALVserveurWebMobile"
var $cookie : Text
var $i : Integer
var $c; $cookies : Collection
This.liste:=New collection
$cookie:=This.getCookie()
$cookies:=Split string($cookie; ";")
For ($i; 0; $cookies.length-1)
$c:=Split string($cookies[$i]; "="; sk trim spaces)
This.liste.push(New object("nom"; $c[0]; "valeur"; $c[1]))
End for
$result:=This.liste
Function Ecrire($attribut : Text; $valeur : Text)
var $cookie : Text
var $timeOut : Integer
$cookie:=$attribut+"="+$valeur
This.setCookie($cookie)
WEB GET OPTION(Web inactive session timeout; $timeOut)
cs._Trace.me.EnvoyerMessages([msgk_event; msgk_log]; "Nouveau cookie"; Current method name; $attribut+" = "+$valeur+" - timeOut session Web "+String($timeOut)+" mn - ID session "+Session.id)
Function Supprimer()
// on ne peut pas supprimer le fichier cookie. Pour invalider l'authentification, on change le date d'expiration du cookie
This.Ecrire("Expires"; "Thu, 01 Jan 1970 00:00:01 GMT")
This.Ecrire("path"; "/")
// -----------------------------
// MARK:Traitement des URL session
// -----------------------------
Function getMobileWebID()->$result : Text
// renvoie le ID de la session mobile
$result:=""
This.Lire()
Case of
: (Not(OB Is defined(This; "liste")))
: (This.liste.query("nom = :1"; "mobileWebID").length=0)
Else
$result:=This.liste.query("nom = :1"; "mobileWebID")[0].valeur
End case
Function getCookie()->$result : Text
var $rang : Integer
ARRAY TEXT($clésEntête; 0)
ARRAY TEXT($valeursEntête; 0)
WEB GET HTTP HEADER($clésEntête; $valeursEntête)
$rang:=Find in array($clésEntête; "Cookie")
If ($rang#-1)
$result:=$valeursEntête{$rang}
End if
Function setCookie($valeur : Text)
var $cookie : Text
$cookie:="Set-Cookie: "+$valeur
WEB SET HTTP HEADER($cookie)
⇧
[class]_CommunFunctions - 30/10/2025 11:54:23
singleton Class constructor()
Function InitProcess()
var ErrorNum : Integer
ErrorNum:=0
ON ERR CALL(Formula(traceHandler).source; ek local) // gestion des erreurs
Function LireLocatedSTR($ID : Integer; $options : Object)->$result : Text
var $newTexte : Text:=""
var $début; $fin : Integer
var $libellé; $texte; $balise : Text
var $UserPrefs : Object
var $c; $cEL : Collection
$texte:=Localized string(String($ID))
// options
Case of
: (Count parameters=1)
// pas d'options
: (($ID>=1) & ($ID<=70999))
// traiter les chaines complexes dans un texte multistyle. Les balises d'éléments HTML sont traitées ailleurs (mécanisme différent)
// v7.4.5 Remarque : traiter toutes les chaines. Les balises ALV sont différentes du mécanisme de 4D : "Utiliser des références dans les textes statiques"
$UserPrefs:=Storage.UserPrefs
// rechercher dans $result une balise d'un type de $c à partir de $début
// une balise est la forme :typeBalise?xxxx:
// d'abord chercher les balises de type xCode, référant un élément de langages
// puis traiter les balises de type xliff dans un texte multistyle
// puis traiter les balises de type uri dans un texte multistyle
$c:=New collection(":xCode"; ":xliff"; ":uri")
For each ($libellé; $c)
$début:=1
While ($début>0)
// chercher la balise
$fin:=Position($libellé; $texte; $début; *)
If ($fin=0)
// c'est fini : arrêter la recherche
$début:=-1
Else
// récupérer la balise
$début:=$fin
$fin:=Position(":"; $texte; $début+1; *)
$balise:=Substring($texte; $début; $fin-$début+1) // balise à remplacer
// récupérer les paramètres
$newTexte:=Substring($balise; 2; Length($balise)-2) // virer les marqueurs (plus propre)
$cEl:=Split string($newTexte; "?"; sk ignore empty strings)
// plusieurs cas
Case of
// il faut avoir trouvé la fin de la balise
: ($fin=0)
$début:=0
$newTexte:=""
cs._Trace.me.Créer(-15085; Current method name; "balise xliff incomplète dans la chaine "+String($ID)).LeverException([msgk_son; msgk_log])
// il faut au moins 1 élément
: ($cEl.length=0)
// effacer la balise
$texte:=Replace string($texte; $balise; "")
// calculer le texte remplaçant la balise
: ($libellé=":xCode")
Case of
// traiter les balises dont la valeur est contextuelle (paramètres de la méthode)
: ($cEl[1]="genre")
$newTexte:="?"
Case of
: (Not(OB Is defined($options; "genre")))
: (Not(OB Is defined($UserPrefs; "Apparence")))
// la langue n'est pas toujours définie (exemple : à l'ouverture de l'application, et avant l'ouverture de session)
// imposer le français
$newTexte:="e"*Num($options.genre)
: ($UserPrefs.Apparence.Formulaire.CodeLangue="fr")
$newTexte:="e"*Num($options.genre)
End case
: ($cEl[1]="plur")
$newTexte:="?"
Case of
: (Not(OB Is defined($options; "plur")))
: (Not(OB Is defined($UserPrefs; "Apparence")))
// la langue n'est pas toujours définie (exemple : à l'ouverture de l'application, et avant l'ouverture de session)
// imposer le français
$newTexte:="s"*Num($options.plur)
: ($UserPrefs.Apparence.Formulaire.CodeLangue="fr")
$newTexte:="s"*Num($options.plur)
: ($UserPrefs.Apparence.Formulaire.CodeLangue="en")
$newTexte:="s"*Num($options.plur)
End case
: ($cEl[1]="param_@")
$newTexte:="?"
Case of
: (Not(OB Is defined($options; $cEl[1])))
Else
$newTexte:=$options[$cEl[1]]
End case
// pour le reste, il faut au moins 2 éléments
: ($cEl.length<3)
// effacer la balise
$newTexte:=""
// une variable, sa valeur est renseignée dans Storage.STR
: ($cEl[1]="variable")
$newTexte:="err :xCode?variable"
Case of
: (Not(OB Is defined(Storage; "STR")))
: (Not(OB Is defined(Storage.STR; $cEl[2])))
// pas créée
$newTexte:="err "+$cEl[2]
Else
// c'est ok
$newTexte:=Storage.STR[$cEl[2]]
End case
End case
: ($libellé=":xliff")
Case of
// une chaine localisée
: ($cEl.length=2)
// une balise xliff peut contenir des éléments calculés => on boucle
$newTexte:=This.LireLocatedSTR(Num($cEl[1]); $options)
// une chaine en ressource
: ($cEl.length=3)
Case of
: ($cEl[1]="4D")
// chaine ressource de 4D
$newTexte:=Localized string($cEl[2])
: ($cEl[1]="ALV")
// chaine ressource de ALV (APP, WEB ...)
$newTexte:=""
If (Not(cs.xSDK.ResourceALV.me.SetVariable(Est Ressource APP; $cEl[2]; Is text; ->$newTexte)))
$newTexte:=$balise
End if
: ($cEl[1]="WEB")
// chaine ressource de ALV (APP, WEB ...)
$newTexte:=""
If (Not(cs.xSDK.ResourceALV.me.SetVariable(Est Ressource WEBMO; $cEl[2]; Is text; ->$newTexte)))
$newTexte:=$balise
End if
Else
// v6.7.1 : "Lire chaîne dans liste" : commande obsolète
$newTexte:=$cEl[2]
End case
End case
: ($libellé=":uri")
// v8.4.5 : suppression de ST FIXER TEXTE. Ce traitement doit se faire après tous les autres
// plusieurs cas
Case of
// il faut au moins 3 éléments
: ($cEl.length<4)
// effacer la balise
$result:=Replace string($result; $balise; "")
Else
// un lien vers un objet ALV
$newTexte:=String(CodeEnreg(Num($cEl[2]); [Num($cEl[3])]))
$newTexte:="<span style=\"-d4-ref-user:'"+$newTexte+"'\">"+$cEl[1]+"</span>"
End case
//// continuer depuis le début (on ne connait pas la longueur de ce qui a été inséré)
//$début:=1
//// pour passer les tests suivants
//$balise:=""
//$newTexte:=""
Else
// on ne sait pas
$newTexte:="err locatedSTR "+String($ID)
End case
// traduire la balise (il peut y en avoir plusieurs)
$texte:=Replace string($texte; $balise; $newTexte)
// continuer
$début:=$début+Length($newTexte)
End if
End while
// balise suivante
End for each
End case
$result:=$texte
Function AjouterObjetA($entité : Object; $data : Object; $attribut : Text)
// stocker l'instance de classe $entité à l'attribut $attribut de $data
var $entitéCopy : Object
Use ($data)
$data[$attribut]:=New shared object
End use
// $data[$attribut] appartient à un autre groupe partagé
Use ($data[$attribut])
// $entité appartient à un groupe partagé
// en faire une copie
$entitéCopy:=OB Copy($entité; ck shared; $data[$attribut])
// $entité est maintenant dans le même groupe partagé que $data[$attribut]
// on peut la mettre dans $data via sa copie
$data[$attribut]:=$entitéCopy
End use
Function RetaillerImage($pict : Pointer; $largeur : Integer; $hauteur : Integer)
// formater l'image $pict aux $largeur / $hauteur max
var $zoom : Real
var $width; $height; $gauche; $haut : Integer
$zoom:=-Scaled to fit prop centered // format d'affichage de l'image
$gauche:=0
$haut:=0
PICTURE PROPERTIES($pict->; $width; $height)
cs.xSDK.Outils.me.CalculerRectangleMedia(->$gauche; ->$haut; ->$largeur; ->$hauteur; $width; $height; ->$zoom)
$pict->:=$pict->*$zoom
⇧
onStartup - 05/11/2025 19:47:30
// ne s'exécute pas dans une base hôte
ON ERR CALL(Formula(traceHandler).source; ek global)
// pour les tests hors base hôte
cs._composant.new().InitVariablesWEB()
CALL WORKER("WK_Composant_WEBMO"; Formula(cs._CommunFunctions.me.InitProcess()))
// installer le dossier racine Webserveur
cs._composant.new().InstallerServeur()
⇧
onExit - 26/10/2025 11:35:52
// ne s'exécute pas dans une base hôte
// exporter le code du composant si pas compilé
ON ERR CALL(Formula(traceHandler).source; ek local)
cs.xSDK.ExportCode4D.new().DémarrerComposant()
⇧
onWebConnection - 28/10/2025 18:35:48
#DECLARE($url : Text; $entete : Text; $IPnavigateur : Text; $IPserveur : Text; $LogIn : Text; $motDePasse : Text)
cs.$serveur.new().surConnexionWeb($url; $entete; $IPnavigateur; $IPserveur; $LogIn; $motDePasse)
⇧
onWebAuthentication - 28/10/2025 18:35:57
#DECLARE($url : Text; $entete : Text; $IPnavigateur : Text; $IPserveur : Text; $LogIn : Text; $motDePasse : Text)->$result : Boolean
$result:=cs.$serveur.new().surAuthentificationWeb($url; $entete; $IPnavigateur; $IPserveur; $LogIn; $motDePasse)
⇧
onHostDatabaseEvent - 05/11/2025 19:47:39
#DECLARE($numEvent : Integer)
Case of
: ($numEvent=On before host database startup)
// ici pas d'interaction avce les autres composants et la BDDmère
ON ERR CALL(Formula(ErrorHandler).source; ek local)
cs._composant.new().InitVariablesWEB()
Use (Storage.System)
Storage.System.estExécutéDansHôte:=True
Storage.System.estExécutéDansAPP:=cs.xSDK.EnvironnementALV.new().estExecuteDansAPP()
End use
// déactiver les ASSERT si le composant est compilé (réactivable par les options d'appel du composant)
SET ASSERT ENABLED(Not(Is compiled mode))
CALL WORKER("WK_Composant_WEBMO"; Formula(cs._CommunFunctions.me.InitProcess()))
: ($numEvent=On after host database startup)
// à faire ici tout est initialisé, en particulier le monde extérieur
ON ERR CALL(Formula(traceHandler).source; ek global)
cs._composant.new().Installer()
: ($numEvent=On before host database exit)
// placer ici le code à exécuter avant le "Sur fermeture" de la base hôte
cs._maintenance.new().Arrêter()
cs.$serveur.new().Arreter()
: ($numEvent=On after host database exit)
// placer ici le code à exécuter après le "Sur fermeture" de la base hôte
End case