[PLUGINS] +maj gis4
[lhc/web/www.git] / www / plugins / saisies / inc / saisies_afficher.php
1 <?php
2
3 /**
4 * Gestion de l'affichage des saisies.
5 *
6 * @return SPIP\Saisies\Afficher
7 **/
8
9 // Sécurité
10 if (!defined('_ECRIRE_INC_VERSION')) {
11 return;
12 }
13
14 /**
15 * Indique si une saisie peut être affichée.
16 *
17 * On s'appuie sur l'éventuelle clé "editable" du $champ.
18 * Si editable vaut :
19 * - absent : le champ est éditable
20 * - 1, le champ est éditable
21 * - 0, le champ n'est pas éditable
22 * - -1, le champ est éditable s'il y a du contenu dans le champ (l'environnement)
23 * ou dans un de ses enfants (fieldsets)
24 *
25 * @param array $champ
26 * Tableau de description de la saisie
27 * @param array $env
28 * Environnement transmis à la saisie, certainement l'environnement du formulaire
29 * @param bool $utiliser_editable
30 * - false pour juste tester le cas -1
31 *
32 * @return bool
33 * Retourne un booléen indiquant l'état éditable ou pas :
34 * - true si la saisie est éditable (peut être affichée)
35 * - false sinon
36 */
37 function saisie_editable($champ, $env, $utiliser_editable = true) {
38 if ($utiliser_editable) {
39 // si le champ n'est pas éditable, on sort.
40 if (!isset($champ['editable'])) {
41 return true;
42 }
43 $editable = $champ['editable'];
44
45 if ($editable > 0) {
46 return true;
47 }
48 if ($editable == 0) {
49 return false;
50 }
51 }
52
53 // cas -1
54 // name de la saisie
55 if (isset($champ['options']['nom'])) {
56 // si on a le name dans l'environnement, on le teste
57 $nom = $champ['options']['nom'];
58 if (isset($env[$nom])) {
59 return $env[$nom] ? true : false;
60 }
61 }
62 // sinon, si on a des sous saisies
63 if (isset($champ['saisies']) and is_array($champ['saisies'])) {
64 foreach ($champ['saisies'] as $saisie) {
65 if (saisie_editable($saisie, $env, false)) {
66 return true;
67 }
68 }
69 }
70
71 // aucun des paramètres demandés n'avait de contenu
72 return false;
73 }
74
75 /**
76 * Génère une saisie à partir d'un tableau la décrivant et de l'environnement.
77 *
78 * @param array $champ
79 * Description de la saisie.
80 * Le tableau doit être de la forme suivante :
81 * array(
82 * 'saisie' => 'input',
83 * 'options' => array(
84 * 'nom' => 'le_name',
85 * 'label' => 'Un titre plus joli',
86 * 'obligatoire' => 'oui',
87 * 'explication' => 'Remplissez ce champ en utilisant votre clavier.'
88 * )
89 * )
90 * @param array $env
91 * Environnement du formulaire
92 * Permet de savoir les valeurs actuelles des contenus des saisies,
93 * les erreurs eventuelles présentes...
94 *
95 * @return string
96 * Code HTML des saisies de formulaire
97 */
98 function saisies_generer_html($champ, $env = array()) {
99 // Si le parametre n'est pas bon, on genere du vide
100 if (!is_array($champ)) {
101 return '';
102 }
103
104 // Si la saisie n'est pas editable, on sort aussi.
105 if (!saisie_editable($champ, $env)) {
106 return '';
107 }
108
109 $contexte = array();
110
111 // On sélectionne le type de saisie
112 $contexte['type_saisie'] = $champ['saisie'];
113 // Identifiant unique de saisie, si present
114 if (isset($champ['identifiant'])) {
115 $contexte['id_saisie'] = $champ['identifiant'];
116 }
117
118 // Peut-être des transformations à faire sur les options textuelles
119 $options = isset($champ['options']) ? $champ['options'] : array();
120 foreach ($options as $option => $valeur) {
121 if ($option == 'datas') {
122 // exploser une chaine datas en tableau (applique _T_ou_typo sur chaque valeur)
123 $options[$option] = saisies_chaine2tableau($valeur);
124 } else {
125 $options[$option] = _T_ou_typo($valeur, 'multi');
126 }
127 }
128
129 // compatibilité li_class > conteneur_class
130 if (!empty($options['li_class'])) {
131 $options['conteneur_class'] = $options['li_class'];
132 }
133
134 // On ajoute les options propres à la saisie
135 $contexte = array_merge($contexte, $options);
136
137 // Si env est définie dans les options ou qu'il y a des enfants, on ajoute tout l'environnement
138 if (isset($contexte['env']) or (isset($champ['saisies']) and is_array($champ['saisies']))) {
139 unset($contexte['env']);
140
141 // on sauve l'ancien environnement
142 // car les sous-saisies ne doivent pas être affectees
143 // par les modification sur l'environnement servant à generer la saisie mère
144 $contexte['_env'] = $env;
145
146 // À partir du moment où on passe tout l'environnement, il faut enlever certains éléments qui ne doivent absolument provenir que des options
147 unset($env['inserer_debut']);
148 unset($env['inserer_fin']);
149 $saisies_disponibles = saisies_lister_disponibles();
150 if (isset($saisies_disponibles[$contexte['type_saisie']]) and is_array($saisies_disponibles[$contexte['type_saisie']]['options'])) {
151 $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);
152 foreach ($options_a_supprimer as $option_a_supprimer) {
153 unset($env[$option_a_supprimer]);
154 }
155 }
156
157 $contexte = array_merge($env, $contexte);
158 }
159 // Sinon on ne sélectionne que quelques éléments importants
160 else {
161 // On récupère la liste des erreurs
162 $contexte['erreurs'] = $env['erreurs'];
163 // On récupère la langue de l'objet si existante
164 if (isset($env['langue'])) {
165 $contexte['langue'] = $env['langue'];
166 }
167 // On ajoute toujours le bon self
168 $contexte['self'] = self();
169 }
170
171 // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ
172 // Si le nom du champ est un tableau indexé, il faut parser !
173 if (isset($contexte['nom']) and preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)) {
174 $contexte['valeur'] = $env[$separe[1]];
175 preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
176 // On va chercher au fond du tableau
177 foreach ($index[1] as $cle) {
178 $contexte['valeur'] = isset($contexte['valeur'][$cle]) ? $contexte['valeur'][$cle] : null;
179 }
180 }
181 // Sinon la valeur est juste celle du nom si elle existe
182 elseif (isset($contexte['nom']) and isset($env[$contexte['nom']])) {
183 $contexte['valeur'] = $env[$contexte['nom']];
184 }
185 // Sinon rien
186 else {
187 $contexte['valeur'] = null;
188 }
189
190 // Si ya des enfants on les remonte dans le contexte
191 if (isset($champ['saisies']) and is_array($champ['saisies'])) {
192 $contexte['saisies'] = $champ['saisies'];
193 }
194
195 // On génère la saisie
196 return recuperer_fond(
197 'saisies/_base',
198 $contexte
199 );
200 }
201
202 /**
203 * Génère une vue d'une saisie à partir d'un tableau la décrivant.
204 *
205 * @see saisies_generer_html()
206 *
207 * @param array $saisie
208 * Tableau de description d'une saisie
209 * @param array $env
210 * L'environnement, contenant normalement la réponse à la saisie
211 * @param array $env_obligatoire
212 * ???
213 *
214 * @return string
215 * Code HTML de la vue de la saisie
216 */
217 function saisies_generer_vue($saisie, $env = array(), $env_obligatoire = array()) {
218 // Si le paramètre n'est pas bon, on génère du vide
219 if (!is_array($saisie)) {
220 return '';
221 }
222
223 $contexte = array();
224
225 // On sélectionne le type de saisie
226 $contexte['type_saisie'] = $saisie['saisie'];
227
228 // Peut-être des transformations à faire sur les options textuelles
229 $options = $saisie['options'];
230 foreach ($options as $option => $valeur) {
231 if ($option == 'datas') {
232 // exploser une chaine datas en tableau (applique _T_ou_typo sur chaque valeur)
233 $options[$option] = saisies_chaine2tableau($valeur);
234 } else {
235 $options[$option] = _T_ou_typo($valeur, 'multi');
236 }
237 }
238
239 // On ajoute les options propres à la saisie
240 $contexte = array_merge($contexte, $options);
241
242 // Si env est définie dans les options ou qu'il y a des enfants, on ajoute tout l'environnement
243 if (isset($contexte['env']) or (isset($saisie['saisies']) and is_array($saisie['saisies']))) {
244 unset($contexte['env']);
245
246 // on sauve l'ancien environnement
247 // car les sous-saisies ne doivent pas être affectees
248 // par les modification sur l'environnement servant à generer la saisie mère
249 $contexte['_env'] = $env;
250
251 // À partir du moment où on passe tout l'environnement, il faut enlever
252 // certains éléments qui ne doivent absolument provenir que des options
253 $saisies_disponibles = saisies_lister_disponibles();
254
255 if (isset($saisies_disponibles[$contexte['type_saisie']]['options'])
256 and is_array($saisies_disponibles[$contexte['type_saisie']]['options'])) {
257 $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);
258 foreach ($options_a_supprimer as $option_a_supprimer) {
259 unset($env[$option_a_supprimer]);
260 }
261 }
262
263 $contexte = array_merge($env, $contexte);
264 }
265
266 // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ
267
268 // On regarde en priorité s'il y a un tableau listant toutes les valeurs
269 if ($env['valeurs'] and is_array($env['valeurs']) and isset($env['valeurs'][$contexte['nom']])) {
270 $contexte['valeur'] = $env['valeurs'][$contexte['nom']];
271 }
272 // Si le nom du champ est un tableau indexé, il faut parser !
273 elseif (preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)) {
274 $contexte['valeur'] = $env[$separe[1]];
275 preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
276 // On va chercher au fond du tableau
277 foreach ($index[1] as $cle) {
278 $contexte['valeur'] = $contexte['valeur'][$cle];
279 }
280 }
281 // Sinon la valeur est juste celle du nom
282 else {
283 // certains n'ont pas de nom (fieldset)
284 $contexte['valeur'] = isset($env[$contexte['nom']]) ? $env[$contexte['nom']] : '';
285 }
286
287 // Si ya des enfants on les remonte dans le contexte
288 if (isset($saisie['saisies']) and is_array($saisie['saisies'])) {
289 $contexte['saisies'] = $saisie['saisies'];
290 }
291
292 if (is_array($env_obligatoire)) {
293 $contexte = array_merge($contexte, $env_obligatoire);
294 }
295
296 // On génère la saisie
297 return recuperer_fond(
298 'saisies-vues/_base',
299 $contexte
300 );
301 }
302
303 /**
304 * Génère, à partir d'un tableau de saisie le code javascript ajouté à la fin de #GENERER_SAISIES
305 * pour produire un affichage conditionnel des saisies ayant une option afficher_si ou afficher_si_remplissage.
306 *
307 * @param array $saisies
308 * Tableau de descriptions des saisies
309 * @param string $id_form
310 * Identifiant unique pour le formulaire
311 *
312 * @return text
313 * Code javascript
314 */
315 function saisies_generer_js_afficher_si($saisies, $id_form) {
316 $i = 0;
317 $saisies = saisies_lister_par_nom($saisies, true);
318 $code = '';
319 $code .= '(function($){';
320 $code .= '$(document).ready(function(){chargement=true;';
321 $code .= 'verifier_saisies_'.$id_form." = function(form){\n";
322 foreach ($saisies as $saisie) {
323 // on utilise comme selecteur l'identifiant de saisie en priorite s'il est connu
324 // parce que conteneur_class = 'tableau[nom][option]' ne fonctionne evidement pas
325 // lorsque le name est un tableau
326 if (isset($saisie['options']['afficher_si']) or isset($saisie['options']['afficher_si_remplissage'])) {
327 ++$i;
328 // retrouver la classe css probable
329 switch ($saisie['saisie']) {
330 case 'fieldset':
331 $class_li = 'fieldset_'.$saisie['options']['nom'];
332 break;
333 case 'explication':
334 $class_li = 'explication_'.$saisie['options']['nom'];
335 break;
336 default:
337 $class_li = 'editer_'.$saisie['options']['nom'];
338 }
339 $afficher_si = isset($saisie['options']['afficher_si']) ? $saisie['options']['afficher_si'] : '';
340 $afficher_si_remplissage = isset($saisie['options']['afficher_si_remplissage']) ? $saisie['options']['afficher_si_remplissage'] : '';
341 $condition = implode("\n", array_filter(array($afficher_si, $afficher_si_remplissage)));
342 // retrouver l'identifiant
343 $identifiant = '';
344 if (isset($saisie['identifiant']) and $saisie['identifiant']) {
345 $identifiant = $saisie['identifiant'];
346 }
347 // On gère le cas @plugin:non_plugin@
348 preg_match_all('#@plugin:(.+)@#U', $condition, $matches);
349 foreach ($matches[1] as $plug) {
350 if (defined('_DIR_PLUGIN_'.strtoupper($plug))) {
351 $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);
352 } else {
353 $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);
354 }
355 }
356 // On gère le cas @config:plugin:meta@ suivi d'un test
357 preg_match_all('#@config:(.+):(.+)@#U', $condition, $matches);
358 foreach ($matches[1] as $plugin) {
359 $config = lire_config($plugin);
360 $condition = preg_replace('#@config:'.$plugin.':'.$matches[2][0].'@#U', '"'.$config[$matches[2][0]].'"', $condition);
361 }
362 // On transforme en une condition valide
363 preg_match_all('#@(.+)@#U', $condition, $matches);
364 foreach ($matches[1] as $nom) {
365 switch ($saisies[$nom]['saisie']) {
366 case 'radio':
367 case 'oui_non':
368 case 'true_false':
369 $condition = preg_replace('#@'.preg_quote($nom).'@#U', '$(form).find("[name=\''.$nom.'\']:checked").val()', $condition);
370 break;
371 case 'case':
372 $condition = preg_replace('#@'.preg_quote($nom).'@#U', '($(form).find(".checkbox[name=\''.$nom.'\']").is(":checked") ? $(form).find(".checkbox[name=\''.$nom.'\']").val() : "")', $condition);
373 break;
374 case 'checkbox':
375 preg_match_all('#@(.+)@\s*==\s*"(.*)"$#U', $condition, $matches2);
376 foreach ($matches2[2] as $value) {
377 $condition = preg_replace('#@'.preg_quote($nom).'@#U', '($(form).find(".checkbox[name=\''.$nom.'[]\'][value='.$value.']").is(":checked") ? $(form).find(".checkbox[name=\''.$nom.'[]\'][value='.$value.']").val() : "")', $condition);
378 }
379 break;
380 default:
381 $condition = preg_replace('#@'.preg_quote($nom).'@#U', '$(form).find("[name=\''.$nom.'\']").val()', $condition);
382 }
383 }
384 if ($identifiant) {
385 $sel = "[data-id='$identifiant']";
386 } else {
387 $sel = ".$class_li";
388 }
389 $code .= "\tif (".$condition.') {$(form).find("'.$sel.'").show(400);} '."\n\t";
390 $code .= 'else {if (chargement==true) {$(form).find("'.$sel.'").hide(400).css("display","none");} else {$(form).find("'.$sel.'").hide(400);};} '."\n";
391 }
392 }
393 $code .= '};';
394 $code .= '$("#afficher_si_'.$id_form.'").parents("form").each(function(){verifier_saisies_'.$id_form.'(this);});';
395 $code .= '$("#afficher_si_'.$id_form.'").parents("form").change(function(){verifier_saisies_'.$id_form.'(this);});';
396 $code .= 'chargement=false;})';
397 $code .= '})(jQuery);';
398
399 return $i > 0 ? $code : '';
400 }
401
402 /**
403 * Lorsque l'on affiche les saisies (#VOIR_SAISIES), les saisies ayant une option afficher_si
404 * et dont les conditions ne sont pas remplies doivent être retirées du tableau de saisies.
405 *
406 * Cette fonction sert aussi lors de la vérification des saisies avec saisies_verifier().
407 * À ce moment là, les saisies non affichées sont retirées de _request
408 * (on passe leur valeur à NULL).
409 *
410 * @param array $saisies
411 * Tableau de descriptions de saisies
412 * @param array|null $env
413 * Tableau d'environnement transmis dans inclure/voi_saisies.html,
414 * NULL si on doit rechercher dans _request (pour saisies_verifier()).
415 *
416 * @return array
417 * Tableau de descriptions de saisies
418 */
419 function saisies_verifier_afficher_si($saisies, $env = null) {
420 // eviter une erreur par maladresse d'appel :)
421 if (!is_array($saisies)) {
422 return array();
423 }
424 foreach ($saisies as $cle => $saisie) {
425 if (isset($saisie['options']['afficher_si'])) {
426 $condition = $saisie['options']['afficher_si'];
427 // On gère le cas @plugin:non_plugin@
428 preg_match_all('#@plugin:(.+)@#U', $condition, $matches);
429 foreach ($matches[1] as $plug) {
430 if (defined('_DIR_PLUGIN_'.strtoupper($plug))) {
431 $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);
432 } else {
433 $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);
434 }
435 }
436 // On gère le cas @config:plugin:meta@ suivi d'un test
437 preg_match_all('#@config:(.+):(.+)@#U', $condition, $matches);
438 foreach ($matches[1] as $plugin) {
439 $config = lire_config($plugin);
440 $condition = preg_replace('#@config:'.$plugin.':'.$matches[2][0].'@#U', '"'.$config[$matches[2][0]].'"', $condition);
441 }
442 // On transforme en une condition valide
443 if (is_null($env)) {
444 $condition = preg_replace('#@(.+)@#U', '_request(\'$1\')', $condition);
445 } else {
446 $condition = preg_replace('#@(.+)@#U', '$env["valeurs"][\'$1\']', $condition);
447 }
448 eval('$ok = '.$condition.';');
449 if (!$ok) {
450 unset($saisies[$cle]);
451 if (is_null($env)) {
452 set_request($saisie['options']['nom'], null);
453 }
454 }
455 }
456 if (isset($saisies[$cle]['saisies'])) { // S'il s'agit d'un fieldset ou equivalent, verifier les sous-saisies
457 $saisies[$cle]['saisies'] = saisies_verifier_afficher_si($saisies[$cle]['saisies'], $env);
458 }
459 }
460
461 return $saisies;
462 }