1$(function(){ 2 afficher_si_init(); 3 onAjaxLoad(afficher_si_init); 4}); 5afficher_si_current_data = ''; 6function afficher_si_init() { 7 $('form:not([data-afficher_si-init])').each(function(){ 8 form = $(this); 9 // Seulement si au moins un afficher_si dedans ! 10 if (this.hasAttribute('data-resume_etapes_futures')) { 11 var resume_etapes_futures = this.getAttribute('data-resume_etapes_futures'); 12 } else { 13 var resume_etapes_futures = ''; 14 } 15 let conteneur_extra = ''; 16 let react = [form]; 17 if (this.hasAttribute('data-afficher_si_conteneur_extra')) { 18 conteneur_extra = this.getAttribute('data-afficher_si_conteneur_extra'); 19 react.push($(conteneur_extra)); 20 } 21 22 if ($(this).find('[data-afficher_si]').length !== 0 || resume_etapes_futures || conteneur_extra) { 23 form.find('.formulaire_spip__etapes').each(function() { 24 $(this).css('min-height', $(this).height()); 25 }); 26 afficher_si_init_chemin_etapes(form); 27 28 afficher_si_set_current_data(form); 29 30 react.forEach(function (r) { 31 r.find('[data-afficher_si]').each(function() { 32 condition = verifier_afficher_si($(this), true); 33 animer_afficher_si($(this), condition, true); 34 }); 35 }); 36 afficher_si_set_etapes_presentation_courante(form); 37 afficher_si_set_etape_suivante(form); 38 39 // Un écouteur sur les champs qui conditionnent d'autres champs 40 $(this).find('textarea, input, select').each(function () { 41 var name = $(this).attr('name'); 42 if (name) { 43 name = afficher_si_normaliser_name(name); 44 if ( 45 form.find('[data-afficher_si*=\''+name+'\']').length 46 || resume_etapes_futures.includes(name) 47 || $(conteneur_extra).find('[data-afficher_si*=\''+name+'\']').length 48 ) { 49 $(this).on('input change', function() { 50 afficher_si_onchange($(this)); 51 }); 52 } 53 } 54 } 55 ); 56 $(this).attr('data-afficher_si-init', true); 57 } 58 }) 59} 60 61/** 62 * Normaliser les names 63 * @param string name 64 * @return return name 65**/ 66function afficher_si_normaliser_name(name) { 67 var name = name.replace('[]', ''); 68 var name = name.replace('_choix_alternatif', ''); 69 return name; 70} 71/** 72 * Ecouteur sur les champ 73 * @param jQuery Object $champ 74**/ 75function afficher_si_onchange($champ) { 76 // Seulement si ce champ a un name 77 if (name = $champ.attr('name')) { 78 var form = $champ.parents('form'); 79 80 let react = [form]; 81 if (form.attr('data-afficher_si_conteneur_extra')) { 82 conteneur_extra = form.attr('data-afficher_si_conteneur_extra'); 83 react.push($(conteneur_extra)); 84 } 85 86 var name = afficher_si_normaliser_name(name); 87 afficher_si_set_current_data(form); 88 89 // Si un autre champ (ou pas) utilise celui-ci dans une condition 90 react.forEach(function (r) { 91 r.find('[data-afficher_si*=\''+name+'\']').each(function(){ 92 condition = verifier_afficher_si($(this)); 93 animer_afficher_si($(this), condition); 94 }) 95 }); 96 afficher_si_set_etapes_presentation_courante(form, name); 97 afficher_si_set_etape_suivante(form, name); 98 } 99} 100function afficher_si_set_current_data(form) { 101 current_data = form.serializeArray();//Le format de retour n'est pas simple, on transforme en tableau associatif 102 afficher_si_current_data = []; 103 $(current_data).each(function() { 104 if (this.name.includes('[]')) { 105 this.name = this.name.replace('[]', ''); 106 if (Array.isArray(afficher_si_current_data[this.name])) { 107 afficher_si_current_data[this.name].push(this.value) 108 } else { 109 afficher_si_current_data[this.name] = [this.value]; 110 } 111 } else { 112 afficher_si_current_data[this.name] = this.value; 113 } 114 if (afficher_si_current_data[this.name] === '@choix_alternatif') { 115 afficher_si_current_data[this.name] = form.find('[name = "' + this.name + '_choix_alternatif' + '"]').val(); 116 afficher_si_current_data[this.name + ':choix_alternatif'] = true;// Usage interne, pas de stabilité de l'API 117 } else { 118 afficher_si_current_data[this.name + ':choix_alternatif'] = false;// Usage interne, pas de stabilité de l'API 119 } 120 }); 121} 122function verifier_afficher_si(saisie, chargement = false) { 123 let condition = saisie.attr('data-afficher_si'); 124 condition = eval(condition); 125 if ( 126 chargement 127 && !condition 128 && (saisie.hasClass('erreur') || $('.erreur', saisie).length) 129 && !saisie.hasClass('saisies-menu-onglets__item') 130 && !saisie.hasClass('saisies-contenu-onglet') 131 ) {//Tjr afficher au chargement s'il y une erreur. Si cela arrive c'est qu'il y a quelque part une incohérence entre l'évaluation JS et l'évaluation PHP des afficher si. Attention ! Ne pas appliquer aux onglets qui ont des classes erreurs, ca c'est volontaire 132 console.log('Attention : saisies masquée par afficher_si avec une erreur...' + saisie.attr('data-id')); 133 return true; 134 } 135 return condition 136} 137function animer_afficher_si(saisie, condition, chargement){ 138 if (condition) { 139 if (!saisie.hasClass('afficher_si_visible')) { 140 saisie.trigger('afficher_si_visible_pre'); 141 saisie.removeClass('afficher_si_masque_chargement').removeClass('afficher_si_masque').addClass('afficher_si_visible').removeAttr('aria-hiden'); 142 if (!saisie.hasClass('afficher_si_sans_visuel')) { 143 afficher_si_show(saisie); 144 } 145 afficher_si_restaure_validation(saisie); 146 saisie.trigger('afficher_si_visible_post'); 147 } 148 } else { 149 if (!saisie.hasClass('afficher_si_masque')) { 150 saisie.trigger('afficher_si_masque_pre'); 151 if (!saisie.hasClass('afficher_si_sans_visuel')) { 152 afficher_si_hide(saisie); 153 } 154 if (chargement) { 155 saisie.addClass('afficher_si_masque_chargement'); 156 } 157 saisie.addClass('afficher_si_masque').removeClass('afficher_si_visible').attr('aria-hiden', true); 158 afficher_si_disable_validation(saisie); 159 saisie.trigger('afficher_si_masque_post'); 160 } 161 } 162} 163/** 164 * Prend les attribut de validation au sein d'une saisie et les supprime
165 * tout en stockant en mémoire dans des data-truc 166 * @param $saisie la saisie (conteneur) 167**/ 168function afficher_si_disable_validation($saisie) { 169 for (attribut of afficher_si_validation_attributs) { 170 if (attribut in afficher_si_validation_attributs_valeurs) { 171 var selecteur = afficher_si_validation_attributs_valeurs[attribut].map((x) => '[' + attribut + '=' + x + ']').join(', '); 172 } else { 173 var selecteur = '[' + attribut + ']'; 174 } 175 var enfants = $saisie.find(selecteur); 176 enfants.each(function() { 177 $(this).attr('data-afficher_si-' + attribut, $(this).attr(attribut)).attr(attribut, null); 178 }); 179 } 180} 181 182/** 183 * Rétabli si besoin les attribut de validation au sein d'une saisie 184 * @param $saisie la saisie (conteneur) 185**/ 186function afficher_si_restaure_validation($saisie) { 187 for (attribut of afficher_si_validation_attributs) { 188 var enfants = $saisie.find('[data-afficher_si-' + attribut + ']'); 189 enfants.each(function() { 190 if ($(this).parents('.afficher_si_masque').length == 0) { 191 $(this).attr(attribut, $(this).attr('data-afficher_si-' + attribut)).attr('data-afficher_si-' + attribut, null); 192 } 193 }); 194 } 195} 196 197 198var afficher_si_validation_attributs = [ 199 'required', 200 'minlength', 201 'maxlength', 202 'min', 203 'max', 204 'type', 205 'step', 206 'pattern' 207]; 208var afficher_si_validation_attributs_valeurs = {'type': ['email', 'url']}; 209// Ref https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation#validation-related_attributes 210 211 212function afficher_si(args) { 213 if (afficher_si_current_data.hasOwnProperty(args['champ'])) { 214 valeur_champ = afficher_si_current_data[args['champ']]; 215 } else { 216 valeur_champ = ''; 217 } 218 valeur = args['valeur']; 219 if (!('modificateur' in args)) { 220 args['modificateur'] = {'fonction' : ''}; 221 } 222 223 // Compat historique == > IN pour données tabulaires ! 224 if ( 225 Array.isArray(valeur_champ) 226 && (args['modificateur']['fonction'] !== 'total') 227 ) { 228 if (args['operateur'] == '==') { 229 args['operateur'] = 'IN'; 230 } else if(args['operateur'] == '!=') { 231 args['operateur'] = '!IN'; 232 } 233 } 234 235 // Si on vérifie un modificateur 'total' est à appliquer sur la valeur du champ de saisie 236 if (args['modificateur']['fonction'] === 'total') { 237 if (Array.isArray(valeur_champ)) { 238 valeur_champ = valeur_champ.length; 239 } else { 240 valeur_champ = 0; 241 } 242 } 243 244 // Si on vérifie un modificateur 'substr' est à appliquer sur la valeur du champ de saisie 245 if (args['modificateur']['fonction'] === 'substr') { 246 // A priori inutile de tester le type car c'est déjà fait dans la fonction PHP 247 if (args['modificateur']['arguments'][1]) { 248 valeur_champ = valeur_champ.substr(args['modificateur']['arguments'][0], args['modificateur']['arguments'][1]); 249 } else { 250 valeur_champ = valeur_champ.substr(args['modificateur']['arguments'][0]); 251 } 252 } 253 254 // Transformation en tableau des valeurs et valeur_champ, si IN/!IN 255 if (args['operateur'] == 'IN' || args['operateur'] == '!IN') { 256 valeur = valeur.split(','); 257 if (!Array.isArray(valeur_champ)) { 258 if (valeur_champ) { 259 valeur_champ = [valeur_champ]; 260 } else { 261 valeur_champ = []; 262 } 263 } 264 } 265 266 // Transformation en entier des valeurs et valeur_champ, si opérateur de comparaison 267 if (['<', '<=', '>=', '>'].includes(args['operateur'])) { 268 valeur = Number(valeur); 269 valeur_champ = Number(valeur_champ); 270 } 271 272 // Et maintenant les test 273 switch (args['operateur']) { 274 case '==': 275 return valeur_champ == valeur; 276 case '!=': 277 return valeur_champ != valeur; 278 case '>': 279 return valeur_champ > valeur; 280 case '>=': 281 return valeur_champ >= valeur; 282 case '<': 283 return valeur_champ < valeur; 284 case '<=': 285 return valeur_champ <= valeur; 286 case 'MATCH': 287 return RegExp(valeur, args.regexp_modif).test(valeur_champ); 288 case '!MATCH': 289 return !RegExp(valeur, args.regexp_modif).test(valeur_champ); 290 case 'IN': 291 return $(valeur).filter(valeur_champ).length ? true : false; 292 case '!IN': 293 return $(valeur).filter(valeur_champ).length ? false : true; 294 default: 295 return valeur_champ ? true : false; 296 } 297} 298 299 300//Pour l'affichage des étapes selon la présentation "étape courante" seulement 301//@param form, le formulaire 302//@param name le nom de la saisie dont la valeur vient juste de changer 303function afficher_si_set_etapes_presentation_courante(form, name='') { 304 var etapes = afficher_si_parse_data_etapes_futures(form); 305 if (!etapes) { 306 return; 307 } 308 form.find('[data-etapes_max]').each(function() { 309 var etape_total = $(this).attr('data-etapes_max'); 310 for (etape in etapes) { 311 var condition = etapes[etape]['afficher_si'] ?? 'true'; 312 if (!name || condition.includes(name)) { 313 $(this).attr('data-' + etape, eval(condition)); 314 } 315 if (condition && !eval($(this).attr('data-' + etape))) { 316 etape_total--; 317 } 318 } 319 $(this).find('.formulaire_spip_etape__total').text(etape_total); 320 }); 321} 322 323// Pour le libellé de l'étape suivante 324//@param form, le formulaire 325//@param name le nom de la saisie dont la valeur vient juste de changer 326function afficher_si_set_etape_suivante(form, name) { 327 var etapes = afficher_si_parse_data_etapes_futures(form); 328 if (!etapes) { 329 return; 330 } 331 332 var label_enregistrer = form.find('button.submit_suivant').attr('data-label_enregistrer'); 333 var titre_retenu = label_enregistrer; 334 // Chercher la première future étape 335 for (etape in etapes) { 336 var afficher_si_etape = etapes[etape]['afficher_si'] ?? 'true'; 337 if (eval(afficher_si_etape)) { 338 titre_retenu = etapes[etape]['label']; 339 break; 340 } 341 } 342 form.find('button.submit_suivant').each(function() { 343 var $span = $(this).find('.btn__label'); 344 // Stocker le modèle pour suivant, si pas deja fait 345 if (!$(this).attr('data-modele')) { 346 $(this).attr('data-modele', $span.html()); 347 } 348 // Puis ajuster le titre, le modèle variant selon que nous passons directement à la validation ou pas 349 if (titre_retenu == label_enregistrer) { 350 $span.html(titre_retenu); 351 } else { 352 $span.html($(this).attr('data-modele')); 353 $span.find('.titre-etape').html(titre_retenu); 354 } 355 }); 356} 357// Recopier les info d'afficher_si présente dans [data-resume_etapes_futures] au sein de chaque etapes futures 358// Le but est de simplifier ainsi le code principal, en se contentant du code de animer_afficher_si() 359// @param jquery obcet form
360function afficher_si_init_chemin_etapes(form) { 361 var etapes = afficher_si_parse_data_etapes_futures(form); 362 if (!etapes) { 363 return; 364 } 365 for (etape in etapes) { 366 var afficher_si_etape = etapes[etape]['afficher_si'] ?? ''; 367 if (afficher_si_etape) { 368 form.find('.etapes__item.' + etape).attr('data-afficher_si', afficher_si_etape).addClass('afficher_si_sans_visuel'); 369 } 370 } 371} 372function afficher_si_parse_data_etapes_futures(form) { 373 var data = form.attr('data-resume_etapes_futures'); 374 if (!data) { 375 return; 376 } 377 var etapes = JSON.parse(data); 378 return etapes; 379}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.