source: spip-zone/_plugins_/Associaspip/trunk/association_options.php @ 68015

Last change on this file since 68015 was 68015, checked in by esj@…, 7 years ago

Associaspip invalidité XHTML: les ID ne doivent pas avoir des valeurs numériques, savoir ici les index SQL, les numéros de téléphone ou autres fautes de frappes. De toutes façons ces ID n'étaient pas référencés, pas la peine d'alourdir les pages pour rien. Quant à la bardée de #SET bien coûteuse en début de squelettes, on pouvait s'en passer comme toujours.

File size: 120.5 KB
Line 
1<?php
2/***************************************************************************\
3 *  Associaspip, extension de SPIP pour gestion d'associations
4 *
5 * @copyright Copyright (c) 2007 Bernard Blazin & Francois de Montlivault
6 * @copyright Copyright (c) 2010 Emmanuel Saint-James
7 *
8 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9\***************************************************************************/
10
11if (!defined('_ECRIRE_INC_VERSION'))
12        return;
13
14
15/*****************************************
16 * Initialisations
17**/
18
19/**
20 * @global array $GLOBALS['association_liste_des_statuts']
21 * @name $association_liste_des_statuts
22 */
23$GLOBALS['association_liste_des_statuts'] =
24  array('sorti','prospect','ok','echu','relance'); // Le premier element indique un ancien membre
25
26/**
27 * @global array $GLOBALS['association_styles_des_statuts']
28 * @name $association_styles_des_statuts
29 */
30$GLOBALS['association_styles_des_statuts'] = array(
31        'echu' => 'impair',
32        'ok' => 'valide',
33        'prospect' => 'prospect',
34        'relance' => 'pair',
35        'sorti' => 'sortie'
36);
37
38/**
39 * @var const _DIR_PLUGIN_ASSOCIATION_ICONES
40 *   Repertoire de base des images (icones/logos/etc) d'Associaspip
41 */
42define('_DIR_PLUGIN_ASSOCIATION_ICONES', _DIR_PLUGIN_ASSOCIATION.'img_pack/');
43
44/**
45 * @global array $GLOBALS['spip_pipeline']['modules_asso']
46 * @name $association_modules
47 */
48if ( !isset($GLOBALS['spip_pipeline']['modules_asso']) )
49        $GLOBALS['spip_pipeline']['modules_asso'] = ''; // definir ce pipeline, sans ecraser sa valeur s'il existe
50
51/**
52 * @var const _ASSOCIASPIP_LIMITE_SOUSPAGE
53 *   Nombre de lignes maximales dans les listes de membres, operations comptables, activites...
54 */
55if (!defined('_ASSOCIASPIP_LIMITE_SOUSPAGE'))
56        define('_ASSOCIASPIP_LIMITE_SOUSPAGE', 30);
57
58/**
59 * @var const _ASSOCIASPIP_AUJOURDHUI_HORAIRE
60 *   Indique s'il faut afficher l'heure en plus de la date
61 */
62if (!defined('_ASSOCIASPIP_AUJOURDHUI_HORAIRE'))
63        define('_ASSOCIASPIP_AUJOURDHUI_HORAIRE', FALSE);
64
65
66/*****************************************
67 * @defgroup association_bouton
68 * Affichage HTML : boutons d'action dans les listing
69 *
70 * @param string $tag
71 *   balise-HTML encadrante (doit fonctionner par paire ouvrante et fermante) ;
72 *   "TD" par defaut car dans Associaspip un tel bouton est genere dans une cellule de tableau
73 * @return string $res
74 *   code HTML du bouton
75** @{ */
76
77/**
78 * boutons act[ion|er] (si page de script indiquee) generique
79 *
80 * @param string $texte
81 *   libelle du bouton
82 * @param string $image
83 *   nom du fichier de l'icone du bouton
84 * @param string $script
85 *   nom du fichier de traitement appele par le bouton (dans un lien "?exec=...")
86 * @param string $exec_args
87 *   autres parametres (outre le nom du script) passes a l'URL
88 * @param string $img_attrs
89 *   autres attributs passes a la balise affichant l'image
90 *
91 * @todo voir s'il est possible d'utiliser plutot la fonction bouton_action($libelle, $url, $class="", $confirm="", $title="") definie dans /ecrire/inc/filtres.php
92 */
93function association_bouton_act($texte, $image, $script='', $exec_args='', $img_attrs='', $tag='td') {
94        $chemin = _DIR_PLUGIN_ASSOCIATION_ICONES.$image; // icone Associaspip
95        if ( !file_exists($chemin) )
96                $chemin = find_in_path($image); // icone alternative
97        if ($texte) {
98                $texte = association_langue($texte);
99                $texte = "\nalt=\"$texte\" title=\"$texte\"";
100        }
101        $res = "<img src=\"$chemin\"$texte $img_attrs />";
102        if ($script) {
103                $h = generer_url_ecrire($script, $exec_args);
104                $res = "<a href='$h'>$res</a>";
105        }
106        return $tag ? "<$tag class='action'>$res</$tag>" : $res;
107}
108
109/**
110 * @name association_bouton_<quoi>
111 * cas specifique de :
112 *
113 * @param string $objet
114 *   nom de l'objet pour lequel on genere le bouton : c'est ce nom, prefixe
115 *   d'un <mot> selon une convention, qui correspond au fichier d'execution
116 *   appele par le lien du bouton
117 * @param int|string $args
118 *   identifiant de l'objet (le nom du parametre est alors "id")
119 *   ou chaine des parametres passes a l'URL
120 */
121//@{
122
123/**
124 * bouton affich[age|er] v[ue|oir] visualis[ation|er]
125 * bouton list[ing|er] (car tres souvent on va mettre l'element en evidence au sein d'une liste)
126 */
127function association_bouton_list($objet, $args='', $tag='td') {
128        switch ($objet) { // infobulles au cas par cas
129                case 'adherent' :
130                        $titre = 'adherent_label_voir_membre';
131                        break;
132                case 'comptes' :
133                        $titre = 'adherent_label_voir_operation';
134                        break;
135                case 'inscrits_activite' :
136                        $titre = 'activite_bouton_voir_liste_inscriptions';
137                        break;
138                case 'membres_groupe' :
139                        $titre = 'voir_membres_groupe';
140                        break;
141                case 'prets' :
142                        $titre = 'prets_nav_gerer';
143                        break;
144                default :
145                        $titre = 'bouton_voir';
146                        break;
147        }
148        $res = association_bouton_act($titre, 'voir-12.png', "$objet", is_numeric($args)?"id=$args":$args, 'width="12" height="12"', $tag);
149        return $res;
150}
151
152/**
153 * bouton edit[ion|er] (modifi[cation|er])
154 */
155function association_bouton_edit($objet, $args='', $tag='td') {
156        $res = association_bouton_act('bouton_modifier', 'edit-12.gif', "edit_$objet", is_numeric($args)?"id_$objet=$args":$args, 'width="12" height="12"', $tag);
157        return $res;
158}
159
160/**
161 * bouton suppr[ession|imer] (efface[ment|r])
162 */
163function association_bouton_suppr($objet, $args='', $tag='td') {
164        $res = association_bouton_act('bouton_supprimer', 'suppr-12.gif', "suppr_$objet", is_numeric($args)?"id_$objet=$args":$args, 'width="12" height="12" class="danger"', $tag);
165        return $res;
166}
167
168/**
169 * bouton paye[ment|r] cotis[ation|er], contribu[tion financiere|er financierement]
170 */
171function association_bouton_paye($objet, $args='', $tag='td') {
172        switch ($objet) { // infobulles au cas par cas
173                case 'ajout_cotisation' :
174                        $titre = 'adherent_label_ajouter_cotisation';
175                        break;
176                case 'edit_activite' :
177                        $titre = 'activite_bouton_maj_inscription';
178                        break;
179                default :
180                        $titre = ' '; // ??
181                        break;
182        }
183        $res = association_bouton_act($titre, 'cotis-12.gif', "$objet", is_numeric($args)?"id=$args":$args, 'width="12" height="12"', $tag); // "ajout_$objet" jusqu'a ce que ajout_participation fusionne avec edit_activite
184        return $res;
185}
186
187//@}
188
189/**
190 * bouton coch[age de|er une] case
191 *
192 * Ce n'est pas un bouton a proprement parler mais il est dans la zone des
193 * boutons et sert a transmettre une liste de valeurs au parametre d'un bouton
194 * normalement situe au bas du tableau..
195 *
196 * @param string $champ
197 *   Nom du champ pour lequel le bouton est genere
198 *   (mettre une chaine vide pour generer un bouton desactive)
199 * @param string $valeur
200 *   Valeur a transmettre pour ce champ
201 * @param string $plus
202 *   Texte supplementaire rajoute
203 *   (utile pour placer d'autres boutons caches dans la cellule)
204 */
205function association_bouton_coch($champ, $valeur='', $plus='', $tag='td') {
206        $res = ($tag?"<$tag class='action'>":'');
207        $res .= $plus.'<input type="checkbox" ';
208        if ( $champ )
209                $res .= 'name="'.$champ.'[]" value="'.$valeur.'"';
210        else
211                $res .= 'disabled="disabled"';
212        $res .= ' />'. ($tag?"</$tag>":'');
213        return $res;
214}
215
216/** @} */
217
218
219/*****************************************
220 * @defgroup association_formater
221 * Affichage HTML d'une chaine localisee et micro-formatee.
222 * La chaine initiale est (essentiellement) issue de la base de donnees apres
223 * passage par un @ref association_recuperer si necessaire.
224 *
225 * @note association_formater_<quoi> s'appelait association_<quoi>fr ;
226 * "fr" initialement pour FRanciser puis est devenu synonyme de FoRmat
227 *
228** @{ */
229
230/**
231 * Affichage d'un nom complet (de membre) suivant la configuration du plugin (i.e. champs geres ou non)
232 *
233 * @param string $civilite
234 *   Civilite (M./Mme/Mle) ou titre (Dr./Pr./Mgr/Gle/etc.)
235 * @param string $prenom
236 *   Prenom(s)
237 * @param string $nom
238 *   Nom de famille
239 * @param string $html_span
240 *   Indique la balise-HTML (paire ouvrante/fermante) servant a grouper le
241 *   resultat. Sa presence (rien par defaut) indique d'appliquer le micro-
242 *   formatage du groupe.
243 * @param string $ps
244 *   Chaine a rajouter entre le nom et le prenom (souvent ", " pour bien les
245 *   distinguer/separer). Dans ce cas (au moins un caractere, meme espace) le
246 *   formatage est a la francaise/chinoise (cas aussi dans de nombreux pays
247 *   francophones) : le prenom est place apres le nom ! Dans le cas contraire,
248 *   il ("prae nomen" en latin, et "first name" en anglais) il "pre"cede le nom
249 *   (de famille/geniteur/origine...)
250 * @return string $res
251 *   Chaine du nom complet du membre, micro-formate ou non.
252 */
253function association_formater_nom($civilite, $prenom, $nom, $html_span='', $ps='') {
254        $res = '';
255        if ($html_span) {
256                $res = '<'.$html_span.' class="'. (($civilite || $prenom)?'n':'fn') .'">';
257        }
258        if ($GLOBALS['association_metas']['civilite'] && $civilite) {
259                $res .= ($html_span?'<span class="honorific-prefix">':'') .$civilite. ($html_span?'</span>':'') .' ';
260        }
261        if ($GLOBALS['association_metas']['prenom'] && $prenom) {
262                $nom1 = ($html_span?'<span class="given-name">':'') .$prenom. ($html_span?'</span>':'');
263        }
264        $nom2 = ($html_span?'<span class="family-name">':'') .$nom. ($html_span?'</span>':'');
265        $res .= ($ps?"$nom2$ps$nom1":"$nom1 $nom2");
266        return $res. ($html_span?"</$html_span>":'');
267}
268
269/**
270 *  Affichage de date localisee et micro-formatee
271 *
272 * @param string $iso_date
273 *   Date au format ISO-8601
274 *   http://fr.wikipedia.org/wiki/ISO_8601#Date_et_heure
275 * @param string $css_class
276 *   Classe(s) CSS (separees par un espace) a rajouter
277 *   Normalement : dtstart|dtend
278 * @param string $format
279 *   Indique le formatage de date souhaite (cf filtre affdate_<format>)
280 * @param string $html_abbr
281 *   Balise-HTML (paire ouvrante/fermante) encadrante
282 *   Par defaut : "abbr"
283 *   http://www.alsacreations.com/tuto/lire/1222-microformats-design-patterns.html#datetime-design-pattern
284 *   Desactiver (chaine vide) pour ne pas micro-formater
285 * @return string $res
286 *   Date formatee
287 */
288function association_formater_date($iso_date, $css_class='', $format='entier', $html_abbr='auto') {
289        if ( !$iso_date || substr_count($iso_date, '0000-00-00') ) // date indeterminee
290                return '';
291        $res = '';
292        if ( $html_abbr=='auto' )
293                $html_abbr = (@$GLOBALS['meta']['html5']?'time':'abbr');
294        if ( $html_abbr )
295                $res = "<$html_abbr ". ($css_class?"class='$css_class' ":'') . ($html_abbr=='time'?'datetime':'title'). "='$iso_date'>";
296        $res .= affdate_base($iso_date, $format?$format:'entier'); // on fait appel a la fonction centrale des filtres SPIP... comme ca c'est traduit et formate dans les langues supportees ! si on prefere les mois en chiffres et non en lettre, y a qu'a changer les chaines de langue date_mois_XX
297        return $res. ($html_abbr?"</$html_abbr>":'');
298}
299
300/**
301 * Affichage de nombre localise
302 *
303 * @param float $nombre
304 *   Valeur numerique au format informatique standard
305 * @param int $decimales
306 *   Nombre de decimales affichees.
307 *   Par defaut : 2
308 * @param string $css_class
309 *   Classe(s) CSS (separees par un espace) a rajouter
310 * @param string $html_abbr
311 *   Balise-HTML (paire ouvrante/fermante) encadrante
312 * @return string $res
313 *   Nombre formatee
314 *
315 * @note Perfectible... Avis aux contributeurs motives...
316 */
317function association_formater_nombre($nombre, $decimales=2, $css_class='', $html_abbr='') {
318        if ( $html_abbr )
319                $res = "<$html_abbr ". ($css_class?"class='$css_class' ":'') ."title='$iso_date'>";
320        else
321                $res = '';
322        setlocale(LC_NUMERIC, utiliser_langue_visiteur() );
323        $locale = localeconv();
324    $res .= number_format(floatval($nombre), $decimales, $locale['decimal_point'], $locale['thousands_sep']);
325        return $res. ($html_abbr?"</$html_abbr>":'');
326}
327
328/**
329 * Affichage de duree localisee et micro-formatee
330 *
331 * @param int|string $nombre
332 *   Valeur numerique de la duree.
333 * @param string $unite
334 *   Lettre indiquant le type de duree affiche : Y|M|W|D|H
335 *   respectivement pour annee|mois|semaine|jour|heures
336 *   Noter qu'il est possible d'utiliser les equivalents francais : A|S|J
337 *   Noter aussi qu'on peut avoir en prime T (horaire seule) ou I (date),
338 *   et dans ce cas ce n'est un nombre entier qui est utilise mais une chaine du temps au format ISO
339 * @param string $html_abbr
340 *   Balise-HTML (paire ouvrante/fermante) encadrante
341 *   Par defaut : "abbr" avec la classe "duration"
342 *   http://www.alsacreations.com/tuto/lire/1222-microformats-design-patterns.html#abbr-design-pattern
343 *   Desactiver (chaine vide) pour ne pas micro-formater
344 * @return string $res
345 *   Duree formatee
346 *
347 * @note les cas de minutes/secondes doivent etre specifie comme des heures au format ISO...
348 */
349function association_formater_duree($nombre, $unite='', $html_abbr='abbr') {
350        $frmt_h = ''; // format human-readable
351        $frmt_m = 'P'; // format machine-parsable
352        if ( is_numeric($unite) ) { // inversion...
353                $pivot = $unite;
354                $unite = $nombre;
355                $nombre = $pivot;
356        }
357        switch(strtoupper($unite)) { // http://ufxtract.com/testsuite/documentation/iso-duration.htm
358                case 'Y' : // year
359                case 'A' : // annee
360                        $nombre = intval($nombre);
361                        $frmt_m .= $nombre.'Y';
362                        $valeur = association_formater_nombre($nombre,0);
363                        $unite = ($nombre<=1) ? _T('local:an') : _T('local:ans');
364                        break;
365                case 'M' : // month/mois
366                        $nombre = intval($nombre);
367                        $frmt_m .= $nombre.'M';
368                        $valeur = association_formater_nombre($nombre,0);
369                        $unite = ($nombre<=1) ? _T('spip:date_un_mois') : _T('spip:date_mois');
370                        break;
371                case 'W' : // week
372                case 'S' : // semaine
373                        $nombre = intval($nombre);
374                        $frmt_m .= $nombre.'W';
375                        $valeur = association_formater_nombre($nombre,0);
376                        $unite = ($nombre<=1) ? _T('spip:date_une_semaine') : _T('spip:date_semaines');
377                        break;
378                case 'D' : // day
379                case 'J' : // jour
380                        $nombre = intval($nombre);
381                        $frmt_m .= $nombre.'D';
382                        $valeur = association_formater_nombre($nombre,0);
383                        $unite = ($nombre<=1) ? _T('local:jour') : _T('spip:date_jours');
384                        break;
385                case 'H' : // hour/heure
386                        $frmt_m .= 'T'.str_replace('00M', '',  str_replace(':','H',$nombre.':00').'M' );
387                        $valeur = association_formater_nombre($nombre,0);
388                        if (intval($nombre)>1)
389                                $unite = _T('spip:date_heures');
390                        elseif (is_numeric($nombre))
391                                $unite = _T('spip:date_une_heure');
392                        elseif (strstr($nombre,'0:00'))
393                                $unite = _T('spip:date_une_minute');
394                        else {
395                                $nombre = explode(':',$nombre);
396                                $frmt_h = _T('spip:date_fmt_heures_minutes', array('h'=>$nombre[0],'m'=>$nombre[1]));
397                        }
398                        break;
399                case 'T' : // (full) ISO Time : no check...
400                        $frmt_m .= 'T'.str_replace( array('HM','HS','MS','00H','00M'), array('H','H','M'), preg_replace('m:m','M',preg_replace('h:h','H',$nombre,1),1).'S' );
401                        $nombre = explode(':',$nombre,2);
402                        if ($nombre[0]>24) { // http://dev.mysql.com/doc/refman/4.1/en/time.html
403                                $nombre['-1'] = intval($nombre[0]/24);
404                                $nombre[0] = $nombre[0]%24;
405                        }
406                        switch($nombre['-1']) { // nombre de jours
407                                case 0:
408                                case '':
409                                        $frmt_h = '';
410                                        break;
411                                case 1:
412                                        $frmt_h = _T('duree_temps', array('nombre'=>1,'unite'=>_T('local:jour')));
413                                        break;
414                                default:
415                                        $frmt_h =  _T('duree_temps', array('nombre'=>association_formater_nombre($nommbre['-1'],0),'unite'=>_T('spip:date_jours')));
416                                        break;
417                        }
418                        if ($nombre[0])
419                                $frmt_h .= ', ';
420                        switch($nombre[0]) { // nombre d'heures
421                                case 0:
422                                        $frmt_h .= '';
423                                        break;
424                                case 1:
425                                        $frmt_h .= _T('duree_temps', array('nombre'=>1,'unite'=>_T('spip:date_une_heure')));
426                                        break;
427                                default:
428                                        $frmt_h .= _T('duree_temps', array('nombre'=>association_formater_nombre($nombre[0],0),'unite'=>_T('spip:date_heures')));
429                                        break;
430                        }
431                        if ($nombre[1])
432                                $frmt_h .= ', ';
433                        switch($nombre[1]) { // nombre de minutes
434                                case 0:
435                                        $frmt_h .= '';
436                                        break;
437                                case 1:
438                                        $frmt_h .= _T('duree_temps', array('nombre'=>1,'unite'=>_T('spip:date_une_minute')));
439                                        break;
440                                default:
441                                        $frmt_h .= _T('duree_temps', array('nombre'=>association_formater_nombre($nombre[1],0),'unite'=>_T('spip:date_minutes')));
442                                        break;
443                        }
444                        if ($nombre[2])
445                                $frmt_h .= ', ';
446                        switch($nombre[2]) { // nombre de secondes
447                                case 0:
448                                        $frmt_h .= '';
449                                        break;
450                                case 1:
451                                        $frmt_h .= _T('duree_temps', array('nombre'=>1,'unite'=>_T('spip:date_une_seconde')));
452                                        break;
453                                default:
454                                        $frmt_h .= _T('duree_temps', array('nombre'=>association_formater_nombre($nombre[2],0),'unite'=>_T('spip:date_secondes')));
455                                        break;
456                        }
457                        $frmt_h .= '. ';
458                        break;
459                case 'I' : // (full) ISO DateTime or Date : no check !!!
460                default :
461                        $frmt_m .= $nombre;
462                        $nombre = explode('T',$nombre,2);
463                        $ladate = explode(':',$nombre[0]);
464                        switch($ladate[0]) { // nombre d'annee
465                                case 0:
466                                case '':
467                                        $frmt_h = '';
468                                        break;
469                                case 1:
470                                        $frmt_h = _T('duree_temps', array('nombre'=>1,'unite'=>_T('local:an')));
471                                        break;
472                                default:
473                                        $frmt_h =  _T('duree_temps', array('nombre'=>association_formater_nombre($ladate[0],0),'unite'=>_T('local:ans')));
474                                        break;
475                        }
476                        if ($ladate[1])
477                                $frmt_h .= ', ';
478                        switch($ladate[1]) { // nombre de mois
479                                case 0:
480                                        $frmt_h .= '';
481                                        break;
482                                case 1:
483                                        $frmt_h .= _T('duree_temps', array('nombre'=>1,'unite'=>_T('spip:date_un_mois')));
484                                        break;
485                                default:
486                                        $frmt_h .= _T('duree_temps', array('nombre'=>association_formater_nombre($ladate[1],0),'unite'=>_T('spip:date_mois')));
487                                        break;
488                        }
489                        if ($ladate[2])
490                                $frmt_h .= ', ';
491                        switch($ladate[2]) { // nombre de jours
492                                case 0:
493                                        $frmt_h .= '';
494                                        break;
495                                case 1:
496                                        $frmt_h .= _T('duree_temps', array('nombre'=>1,'unite'=>_T('local:jour')));
497                                        break;
498                                default:
499                                        $frmt_h .= _T('duree_temps', array('nombre'=>association_formater_nombre($ladate[2],0),'unite'=>_T('spip:date_jours')));
500                                        break;
501                        }
502                        if (count($lheure))
503                                $frmt_h .= ', ';
504                        $lheure = explode(':',$nombre[1]);
505                        switch($lheure[0]) { // nombre d'heures
506                                case 0:
507                                        $frmt_h .= '';
508                                        break;
509                                case 1:
510                                        $frmt_h .= _T('duree_temps', array('nombre'=>1,'unite'=>_T('spip:date_une_heure')));
511                                        break;
512                                default:
513                                        $frmt_h .=  _T('duree_temps', array('nombre'=>association_formater_nombre($lheure[0],0),'unite'=>_T('spip:date_heures')));
514                                        break;
515                        }
516                        if ($lheure[1])
517                                $frmt_h .= ', ';
518                        switch($lheure[1]) { // nombre d'heures
519                                case 0:
520                                        $frmt_h .= '';
521                                        break;
522                                case 1:
523                                        $frmt_h .= _T('duree_temps', array('nombre'=>1,'unite'=>_T('spip:date_une_minute')));
524                                        break;
525                                default:
526                                        $frmt_h .=  _T('duree_temps', array('nombre'=>association_formater_nombre($lheure[1],0),'unite'=>_T('spip:date_minutes')));
527                                        break;
528                        }
529                        if ($lheure[2])
530                                $frmt_h .= ', ';
531                        switch($lheure[2]) { // nombre d'heures
532                                case 0:
533                                        $frmt_h = '';
534                                        break;
535                                case 1:
536                                        $frmt_h = _T('duree_temps', array('nombre'=>1,'unite'=>_T('spip:date_une_seconde')));
537                                        break;
538                                default:
539                                        $frmt_h =  _T('duree_temps', array('nombre'=>association_formater_nombre($lheure[2],0),'unite'=>_T('spip:date_secondes')));
540                                        break;
541                        }
542                        $frmt_h .= '. ';
543                        break;
544        }
545        if (!$frmt_h)
546                $frmt_h = _T('asso:duree_temps', array('nombre'=>$valeur, 'unite'=>$unite) );
547        return $html_abbr ? "<$html_abbr class='duration' title='". htmlspecialchars($frmt_m, ENT_QUOTES, $GLOBALS['meta']['charset']). "'>$frmt_h</$html_abbr>" : $frmt_h;
548}
549
550/**
551 * Affichage de prix (montant et devise) localisee et micro-formatee
552 *
553 * @param float|int $montant
554 *   Montant (valeur chiffree) correspondant au prix
555 * @param string $type
556 *   Nature du montant : non visible, est utilise comme classe semantique complementaire
557 * @param string $devise_code
558 *   Trigramme representant le code ISO-4217 de la devise
559 *   http://fr.wikipedia.org/wiki/ISO_4217
560 *   Par defaut : la code defini dans le fichier de langues, sinon EUR
561 * @param string $devise_symb
562 *   Symbole ou nom generique abrege de la devise
563 *   Par defaut : le symbole defini dans le fichier de langues si defini, sinon le code.
564 * @param string $html_span
565 *   Balise-HTML (paire ouvrante/fermante) encadrant l'ensemble
566 *   Par defaut : "span" avec les classes "money price"
567 *   http://www.alsacreations.com/tuto/lire/1222-microformats-design-patterns.html#value-class-pattern
568 *   Desactiver (chaine vide) pour ne pas micro-formater
569 * @param string $html_abbr
570 *   Balise-HTML (paire ouvrante/fermante) encadrant chaque sous-partie
571 *   Par defaut : "abbr" avec les classes "amount" et "currency"
572 * @return string $res
573 *   Duree formatee
574 *
575 * @note On n'utilise pas la fontcion PHP money_format() --qui ne fonctionne pas
576 * sous Windows-- car on veut micro-formater avec une devise fixee par la
577 * configuration (en fait les chaines de langue) du plugin
578 */
579function association_formater_prix($montant, $type='', $devise_code='', $devise_symb='', $html_abbr='abbr', $html_span='span') {
580        $res = '';
581        if ($html_span)
582                $res .= "<$html_span class='money price $type'>"; // la reference est "price" <http://microformats.org/wiki/hproduct> (reconnu par les moteurs de recherche), mais "money" <http://microformats.org/wiki/currency-brainstorming> est d'usage courant aussi
583        $montant = ($html_abbr?"<$html_abbr class='amount' title='$montant'>":'') . association_formater_nombre($montant) . ($html_abbr?"</$html_abbr>":'');
584        if ( !$devise_code ) {
585                $devise_code = _T('asso:devise_code_iso');
586                if ( !$devise_code )
587                        $devise_code = 'EUR';
588                $devise_symb = _T('asso:devise_symbole');
589        }
590        if ( !$devise_symb ) {
591                if ( function_exists('formater_devise') ) // plugin "Devise" est actif
592                        $devis_symp = formater_devise($devise_code, '%N');
593                else
594                        $devise_symb = $devise_code;
595        }
596        $devise = ($html_abbr ? "<$html_abbr class='currency' title='". htmlspecialchars($devise_code, ENT_QUOTES, $GLOBALS['meta']['charset']) .'\'>' : '') . $devise_symb . ($html_abbr?"</$html_abbr>" :'');
597        $res .= _T('asso:devise_montant', array('montant'=>$montant, 'devise'=>$devise) );
598        return $html_span ? "$res</$html_span>" : $res;
599}
600
601/**
602 * Affichage d'un texte formate
603 *
604 * @param string $texte
605 *   Le texte brut initial
606 * @param string $filtre
607 *   Filtre SPIP a appliquer au texte.
608 *   Pour les filtres avec parametre, il faut utiliser une liste debutant par le
609 *   nom du filtre suivi des parametres.
610 * @param string $html_span
611 *   Balise-HTML (paire ouvrante/fermante) encadrante
612 * @param string $css_class
613 *   Classe(s) CSS (separees par un espace) a rajouter
614 *   N'est (ne sont) prise(nt) en compte que si un tag-HTML est specifie
615 * @return string $res
616 *   Texte formate
617 * @note
618 *   http://spipistrelle.clinamen.org/spip.php?article16
619 */
620function association_formater_texte($texte, $filtre='', $css_class='', $html_span='' ) {
621        $res = '';
622        if ( $css_class && !$html_span )
623                $html_span = 'span';
624        if ( $html_span )
625                $res = "<$html_span". ($css_class?" class='$css_class' ":'') .'>';
626        include_spip('inc/texte'); // pour nettoyer_raccourci_typo
627        if ( is_array($filtre) ) {
628                $params = $filtre;
629                $filtre = array_shift($params);
630        } else {
631                $params = array();
632        }
633        $ok = array_unshift($params, $texte);
634        $res .= $filtre?call_user_func_array($filtre, $params):$texte;
635        return $res. ($html_span?"</$html_span>":'');
636}
637
638/**
639 * Affiche une puce de couleur carree nommee puce-*.gif
640 *
641 * @param string $statut
642 *   Valeur du "statut" a iconifier
643 * @param string|array $icone
644 *   Nom (couleur) de la puce parmis celles disponibles : orange, rouge, vert, poubelle...
645 *   Tableau associant chaque statut a un nom de puce...
646 * @param string $acote
647 *   Legende placee a cote de l'icone
648 * @return string
649 *   Dessin et texte
650 */
651function association_formater_puce($statut, $icone,  $acote='', $img_attrs='') {
652        if ( is_array($icone) )
653                $icone = $icone[$statut];
654        if (!$statut) $img_attrs .= " alt=' '";
655        return association_bouton_act($statut, 'puce-'.$icone.'.gif', '', '', $img_attrs, '').' '. association_langue($acote) ; // c'est comme un bouton... sans action/lien...
656}
657
658/**
659 *  Affichage de l'horodatage localisee et micro-formatee
660 *
661 * @param string $iso_date
662 *   Date au format ISO-8601
663 *   http://fr.wikipedia.org/wiki/ISO_8601#Date_et_heure
664 * @param string $css_class
665 *   Classe(s) CSS (separees par un espace) a rajouter
666 *   Normalement : dtstart|dtend
667 * @param string $html_abbr
668 *   Balise-HTML (paire ouvrante/fermante) encadrante
669 *   Par defaut : "abbr"
670 *   http://www.alsacreations.com/tuto/lire/1222-microformats-design-patterns.html#datetime-design-pattern
671 *   Desactiver (chaine vide) pour ne pas micro-formater
672 * @return string $res
673 *   Date formatee
674 */
675function association_formater_heure($iso_date, $css_class='', $html_abbr='auto') {
676        $res = '';
677        if ( $html_abbr=='auto' )
678                $html_abbr = ($GLOBAL['meta']['html5']?'time':'abbr');
679        if ( $html_abbr )
680                $res = "<$html_abbr ". ($css_class?"class='$css_class' ":'') . ($html_abbr=='time'?'datetime':'title'). "='$iso_date'>";
681        $res .= affdate_heure($iso_date); // on fait appel a la fonction centrale des filtres SPIP... comme ca c'est traduit et formate dans les langues supportees ! si on prefere les mois en chiffres et non en lettre, y a qu'a changer les chaines de langue date_mois_XX
682        return $res . ($html_abbr?"</$html_abbr>":'');
683}
684
685/**
686 * Affichage d'un caracteristique ou d'un code
687 *
688 * @param string $code
689 *   La valeur de la caracteristique
690 * @param string|array $type
691 *   Le type de caracteristique, non affiche (utilise comme classe CSS)
692 *   L'affichage a effectuer indice par le type de caracteristique
693 * @param bool $p_v
694 *   Indique s'il s'agit d'un numero de serie (faux) ou d'un autre genre de parametre (vrai)
695 * @param string $html_span
696 *   Balise-HTML (paire ouvrante/fermante) encadrante
697 *   Par defaut "span"
698 * @return string $res
699 *   Texte formate
700 * @note
701 *   http://microformats.org/wiki/hproduct-proposal#Schema
702 */
703function association_formater_code($code, $type='x-associaspip', $p_v=TRUE, $html_span='span' ) {
704        $res = $html_span  ? ("<$html_span class='". ($p_v?'p-v':'identifier') ."'>") : '';
705        if ( is_string($type) ) { // label implied
706                $res .= "<span class='". ($p_v?'property':'type') ."$type' title='$type'>$code</span>";
707        } else { // label explicit
708                $res .= "<abbr class='". ($p_v?'property':'type') ."' title='$type'>$type</abbr> <span class='value'>$code</span>";
709        }
710        return $res. ($html_span?"</$html_span>":'');
711}
712
713/**
714 * Afficher le nom ou le lien sur un objet a partir de son id
715 *
716 * @param int $id
717 *   Valeur de l'identifiant pour faire le lien ou recuperer le nom
718 * @param string|array $nom
719 *   Le pseudonyme a afficher (directement donnee) ; ou
720 *   La liste de : la table dans laquelle la recuperer, le champ le contenant
721 *   (par defaut "titre") et la cle primaire a utiliser pour la requete (par
722 *   defaut "id_auteur"). Le cas particulier de la liste vide permet de generer
723 *   le nom complet du membre ayant l'ID fourni.
724 * @param string $lien
725 *   Nom de l'objet pour lequel on genere le lien sous forme de raccourci SPIP
726 * @param string $html_span
727 *   Balise HTML encadrante (paire ouvrante/fermante) a utiliser pour encadrer
728 *   l'ensemble. Par defaut : "span". Il faut mettre un chaine vide pour ne pas
729 *   microformater...
730 * @return string $res
731 *   Code HTML correspondant
732 *
733 * @note : etait association_calculer_lien_nomid
734 * En fait c'est pour les modules dons/ventes/activites/prets ou l'acteur (donateur/acheteur/inscrit/emprunteur)
735 * peut etre un membre/auteur (son id_acteur est alors renseigne) mais pas
736 * forcement son nom (qui peut etre different)
737 * ou peut etre une personne exterieure a l'association (on a juste le nom alors
738 * obligatoire)
739 */
740function association_formater_idnom($id, $nom='', $lien='', $html_span='span') {
741        $res = '';
742        if ( is_array($nom) ) { // requeter le nom... (rajoute de la charge sur la base de donnees)
743                $table = ($nom[0] ? $nom[0] : ($nom['table'] ? $nom['table'] : ($nom['from'] ? $nom['from'] : ($nom['tables']?$nom['tables']:'spip_asso_membres') ) ) ) ; // on recupere le nom de la table a interroger
744                if ( $table=='spip_asso_membres' || $table=='asso_membres' ) { // cas special d'un membre
745                        $membre = sql_fetsel('*', 'spip_asso_membres', "id_auteur=$id");
746                        $res = association_formater_nom($membre['sexe'], $membre['prenom'], $membre['nom_famille'], $html_span);
747                } else { // cas general
748                        $champ = ($nom[1] ? $nom[1] : ($nom['field'] ? $nom['field'] : ($nom['select'] ? $nom['select'] : (($table=='spip_auteurs' || $table=='auteurs')?'nom':'titre') ) ) ) ; // on recupere le nom du champ contenant le nom recherche
749                        $clef = ($nom[2] ? $nom[2] : ($nom['pk'] ? $nom['pk'] : ($nom['id'] ? $nom['id'] : 'id_auteur' ) ) ) ; // on recupere le nom du champ contenant le nom recherche
750                        $nom = sql_getfetsel($champ, $table, "$clef=".sql_quote($id) );
751                        if ( $nom )
752                                $res = ($html_span?"<$html_span class='n'>":'') . $nom . ($html_span?"</$html_span>":'');
753                        elseif ( $lien=='membre')
754                                //association_formater_idnom($id, array(), $lien, $html_span);
755                                $res = "membre$id";
756                }
757        } elseif ( $nom ) { // utiliser nom...
758                $res = ($html_span?"<$html_span class='n'>":'') .$nom. ($html_span?"</$html_span>":'');
759        }
760        if ( $lien ) {
761                $res = propre('['.$res."->$lien$id]");
762        }
763        return $res;
764}
765
766/**
767 * Affiche une icone nommee type_*_*.???
768 *
769 * @param string $classe
770 *   Nom du type d'icone. (correspond au CLASS microformat)
771 * @param string|array $valeur
772 *   Nom du sous-type d'icove. (correspond au TITLE microformat)
773 * @param string $sep
774 *   Separateur place entre les icones
775 * @return string
776 *   Dessin et texte
777 */
778function association_formater_typecoord($classe, $valeur, $sep=' ') {
779        include_spip('coordonnees_fonctions'); // pour utiliser les filtres du plugin "Coordonnees"
780        if ( function_exists('logo_type_') ) // bonne version du plugin "Coordonnees" activee
781                return logo_type_($classe, $valeur, $sep).$sep;
782        global $formats_logos;
783        $types = explode(',', $valeur);
784        $res = '';
785        foreach ($types as $type) {
786                $type = strtolower($type);
787                $lang =  _T('coordonnees:type'. ($classe?"_$classe":'') . ($valeur?"_$valeur":'') );
788                foreach ($formats_logos as $format) { // @file ecrire/inc/chercher_logo.php
789                        $fichier = "images/type_$classe". ($type?"_ $type":'') .".$format";
790                        if ( $chemin = find_in_path($fichier) )
791                        $img = $chemin;
792                }
793                if ($img)
794                        $res .= "<img class='type' src='$img' alt='$type' title='". $lang ."' />$sep"; // $res .= association_bouton_act($type, $img, '', '', '', '') ; // c'est comme un bouton... sans action/lien...
795                elseif ($type)
796                        $res .= "<abbr class='type' title='$type'>". $lang ."</abbr>$sep";
797        }
798        return $res;
799}
800
801/**
802 * Affichage micro-formate de liste de numeros de telephones
803 *
804 * @param array $id_objets
805 *   Liste des (listes de) numeros de telephones a formater, ou
806 *   liste des ID dont on doit formater les numeros (voir parametre suivant)
807 * @param string $objet
808 *   Indique le type d'objet dont les ID sont passes afin de recuperer les
809 *   numeros associes a ces objets. Quand rien n'est indique c'est que c'est la
810 *   liste de liste des numeros qui est directement fournie.
811 *   (ceci est prevu pour etendre facilement l'usage de la fonction si necessaire,
812 *   vaut "auteur" par defaut)
813 * @param string $html_span
814 *   Balise-HTML (paire ouvrante/fermante) encadrant l'ensemble
815 *   Par defaut : "div" avec la classe "tel" (ne rien mettre pour desactiver)
816 * @param string $href_pre
817 *   Protocole a utiliser pour faire un lien cliquable sur le numero
818 *   Par defaut : "tel:" comme preconise par la RFC 3966
819 *   Ne rien mettre pour desactiver la creation de lien.
820 * @param string $href_post
821 *   Complement du precedant dans le cas de certains protocoles
822 *   Par exemple, avec $href_pre='sip:' on a $href_post='@ip.ou.hote.passerelle;user=phone'
823 * @param string $sep
824 * @return array $telephones_string
825 *   Liste des numeros formates en HTML.
826 *   Cette fonction s'occupe surtout du balisage (micro-formate) ;
827 *   la localisation "visuelle" du numero est confie au modele coordonnees_telephone
828 * @note
829 *   http://microformats.org/wiki/hcard-fr#adr_tel_email_types
830 *   http://microformats.org/wiki/hcard-fr#valeurs_sous-propri.C3.A9t.C3.A9_type
831 *   http://microformats.org/wiki/hcard-fr#Lisible_par_Humain_vs._Machine
832 *   http://microformats.org/wiki/vcard-suggestions#TEL_Type_Definition
833 */
834function association_formater_telephones($id_objets, $objet='auteur', $html_span='div', $href_pre='tel:', $href_post='', $sep=' ') {
835        $id_objets = association_recuperer_liste($id_objets, FALSE);
836        if ($objet) { // ancien comportement : ce sont les id_auteur qui sont transmis
837                $telephones_array = array(); // initialisation du tableau des donnees
838                $trouver_table = charger_fonction('trouver_table', 'base');
839                if ( $trouver_table('numeros') && $trouver_table('numeros_liens') ) { // le plugin "Coordonnees" est installe (active ou pas)
840                        foreach ($id_objets as $id_objet) { // prepare la structure du tableau renvoye
841                                $telephones_array[$id_objet] = array();
842                        }
843                        $query = sql_select('l.id_objet, l.type, n.*','spip_numeros AS n INNER JOIN spip_numeros_liens AS l ON l.id_numero=n.id_numero', sql_in('l.id_objet', $id_objets)." AND l.objet='$objet' ");
844                        while ($data = sql_fetch($query)) { // on recupere tous les numeros dans un tableau de tableaux
845                                $telephones_array[$data['id_objet']][] = $data;
846                        }
847                        sql_free($query);
848                }
849        } else { // on a deja la liste des numeros !
850                $telephones_array = $id_objets;
851        }
852        $telephones_string = array();  // initialisation du tableau renvoye
853        foreach ($telephones_array as $id_objet => $telephones) { // on cree la liste de chaines de numeros
854                $telephones_string[$id_objet] = ''; // initialisation de la chaine renvoyee
855                foreach ($telephones as $telephone) { // formater chaque numero
856                        if ( !is_array($telephone) ) {
857                                $telephone['numero'] = $telephone;
858                        }
859                        if ($html_span) { // formatage HTML avec microformat
860                                $telephones_string[$id_objet] =  "<$html_span class='tel'>". association_formater_typecoord('tel', $telephone['type']);
861                                $tel_num = ($telephone['pays']?"+$telephone[pays]$telephone[region]$telephone[numero]":$telephone['numero']);
862                                $telephones_string[$id_objet] .=  ($href_pre?("<a title='". _T('asso:composer_le') ." $tel_num' href='$href_pre"):"<abbr title='"). preg_replace('/[^\d+]/', '', $tel_num) . ($href_pre?$href_post:'') ."' class='value'>";
863                                unset($telephone['type']); // ne devrait plus etre traite par le modele
864                                unset($telephone['id_objet']); // ne devrait plus etre traite par le modele
865                                unset($telephone['id_numero']); // ne devrait pas etre utilise par le modele
866                        }
867                        $telephone['_spc'] = $space; // parametre supplementaire pour le modele
868                        $telephones_string[$id_objet] .=  recuperer_fond("modeles/coordonnees_telephone", $telephone) .($html_span?('</'.($href_pre?'a':'abbr')."></$html_span>\n"):'') .$sep;
869                }
870        }
871        return $telephones_string;
872}
873
874/**
875 * Affichage micro-formate de liste d'adresses postales
876 *
877 * @param array $id_objets
878 *   Liste des (listes de) numeros d'adresses a formater, ou
879 *   liste des ID dont on doit formater les numeros (voir parametre suivant)
880 * @param string $objet
881 *   Indique le type d'objet dont les ID sont passes afin de recuperer les
882 *   numeros associes a ces objets. Quand rien n'est indique c'est que c'est la
883 *   liste de liste des numeros qui est directement fournie.
884 *   (ceci est prevu pour etendre facilement l'usage de la fonction si necessaire,
885 *   vaut "auteur" par defaut)
886 * @param string $html_span
887 *   Balise-HTML (paire ouvrante/fermante) encadrant l'ensemble
888 *   Par defaut : "div" avec la classe "adr" (ne rien mettre pour desactiver)
889 * @param string $newline
890 *   Separateur de ligne utilise par le modele de presentation localisee (cf. note)
891 *   Par defaut : "<br />" puisque le formatage est en HTML.
892 * @param string $space
893 *   Espaceur de blocs utilise par le modele de presentation localisee (cf. note)
894 *   Par defaut : "&nbsp;" puisque le formatage est en HTML
895 * @return array $adresses_string
896 *   Liste des adresses formates en HTML.
897 *   Cette fonction s'occupe surtout du balisage (micro-formate) ;
898 *   la disposition des elements d'adresse est confie. au modele coordonnees_adresse
899 * @note
900 *   http://microformats.org/wiki/hcard-fr#adr_tel_email_types
901 *   http://microformats.org/wiki/hcard-fr#valeurs_sous-propri.C3.A9t.C3.A9_type
902 *   http://microformats.org/wiki/hcard-fr#Lisible_par_Humain_vs._Machine
903 *   http://microformats.org/wiki/vcard-suggestions#TEL_Type_Definition
904 *   http://microformats.org/wiki/adr
905 *   http://microformats.org/wiki/adr-cheatsheet
906 */
907function association_formater_adresses($id_objets, $objet='auteur', $html_span='div', $newline='<br />', $espace='&nbsp;') {
908        $id_objets = association_recuperer_liste($id_objets, FALSE);
909        if ($objet) { // ancien comportement : ce sont les id_auteur qui sont transmis
910                $adresses_array = array(); // initialisation du tableau des donnees
911                $trouver_table = charger_fonction('trouver_table', 'base');
912                if ( $trouver_table('spip_adresses') && $trouver_table('spip_adresses_liens') ) { // le plugin "Coordonnees" est installe (active ou pas)
913                        foreach ($id_objets as $id_objet) { // prepare la structure du tableau renvoye
914                                $adresses_array[$id_objet] = array();
915                        }
916                        $query = sql_select("l.id_objet, l.type, a.*, a.pays AS code_pays, '' AS nom_pays ",'spip_adresses AS a INNER JOIN spip_adresses_liens AS l ON l.id_adresse=a.id_adresse', sql_in('l.id_objet', $id_objets)." AND l.objet='$objet' ");
917                        while ($data = sql_fetch($query)) { // on recupere tous les numeros dans un tableau de tableaux
918                                $adresses_array[$data['id_objet']][] = $data;
919                        }
920                        sql_free($query);
921                } elseif ( $trouver_table('spip_gis') && $trouver_table('spip_gis_liens') ) { // le plugin "GIS" est installe (active ou pas)
922                        foreach ($id_objets as $id_objet) { // prepare la structure du tableau renvoye
923                                $adresses_array[$id_objet] = array();
924                        }
925                        $query = sql_select("l.id_objet, l.type, a.*, a.pays AS nom_pays, adresse AS voie ",'spip_adresses AS a INNER JOIN spip_adresses_liens AS l ON l.id_gis=a.id_gis', sql_in('l.id_objet', $id_objets)." AND l.objet='$objet' ");
926                        while ($data = sql_fetch($query)) { // on recupere tous les numeros dans un tableau de tableaux
927                                $adresses_array[$data['id_objet']][] = $data;
928                        }
929                        sql_free($query);
930                }
931        } else { // on a deja la liste des adresses !
932                $adresses_array = $id_objets;
933        }
934        $adresses_string = array();  // initialisation du tableau renvoye
935        foreach ($adresses_array as $id_objet => $adresses) {  // on cree la liste de chaines d'adresses
936                $adresses_string[$id_objet] = ''; // initialisation de la chaine renvoyee
937                foreach ($adresses as $adresse) { // chaque adresse est forcement un tableau bien qu'on le verifie pas
938                        if ($html_span) { // formatage HTML avec microformat
939                                $adresses_string[$id_objet] =  "<$html_span id='$adresse[id_adresse]' class='adr'>". association_formater_typecoord('adr', $adresse['type']);
940                                if ($adresse['voie'])
941                                        $adresse['voie'] = "<span class='street-address'>$adresse[voie]</span>";
942                                if ($adresse['ville'])
943                                        $adresse['ville'] = "<span class='locality'>$adresse[ville]</span>";
944                                if ($adresse['complement'])
945                                        $adresse['complement'] = "<span class='extended-address'>$adresse[complement]</span>";
946                                if ($adresse['region'])
947                                        $adresse['region'] = "<span class='region'>$adresse[region]</span>";
948                                if ($adresse['code_postal'])
949                                        $adresse['code_postal'] = "<span class='postal-code'>$adresse[code_postal]</span>";
950                                if ($adresse['boite_postale'])
951                                        $adresse['boite_postale'] = "<span class='post-office-box'>$adresse[boite_postale]</span>";
952                                if ( !$adresse['nom_pays'] && $adresse['code_pays']!=$GLOBALS['association_metas']['pays'] )
953                                        if ($adresse['code_pays']) {
954                                                if ( is_numeric($adresse['code_pays']) && $trouver_table('spip_geo_pays' ) ) // tenter de recuperer le nom avec le plugin "Geographie"
955                                                        $adresse['nom_pays'] = sql_getfetsel('nom', 'spip_geo_pays', "id_pays=$adresse[code_pays]");
956                                                elseif ( $trouver_table('spip_geo_pays') ) // tenter de recuperer le nom avec le plugin "Pays"
957                                                        $adresse['nom_pays'] = sql_getfetsel('nom', 'spip_pays', 'code='.sql_quote($adresse['code_pays']) );
958                                                else // un code langue ?
959                                                        $adresse['nom_pays'] = _T($adresse['code_pays']);
960                                        }
961                                if ($adresse['nom_pays'])
962                                        $adresse['pays'] = "<span class='country-name'>$adresse[nom_pays]</span>";
963                                unset($adresse['type']); // ne devrait plus etre traite par le modele
964                                unset($adresse['id_objet']); // ne devrait plus etre traite par le modele
965                                unset($adresse['id_adresse']); // ne devrait pas etre utilise par le modele
966                        }
967                        $adresse['_nl'] = $newline; // parametre supplementaire pour le modele
968                        $adresse['_spc'] = $space; // parametre supplementaire pour le modele
969                        $adresses_string[$id_objet] .=  recuperer_fond('modeles/coordonnees_adresse', $adresse) .($html_span?"</$htm_span>\n":'');
970                }
971        }
972        return $adresses_string;
973}
974
975/**
976 * Affichage micro-formate de liste d'adresses de courriel
977 *
978 * @param array $id_objets
979 *   Liste des (listes de) emails/mels a formater, ou
980 *   liste des ID dont on doit formater les mails (voir parametre suivant)
981 * @param string $objet
982 *   Indique le type d'objet dont les ID sont passes afin de recuperer les
983 *   numeros associes a ces objets. Quand rien n'est indique c'est que c'est la
984 *   liste de liste des numeros qui est directement fournie.
985 *   (ceci est prevu pour etendre facilement l'usage de la fonction si necessaire,
986 *   vaut "auteur" par defaut)
987 * @param string $html_span
988 *   Balise-HTML (paire ouvrante/fermante) encadrant l'ensemble avec lien cliquable
989 *   Par defaut : "div" avec la classe "email" (ne rien mettre pour desactiver)
990 * @return array $emails_string
991 *   Liste des courriels formates en HTML.
992 * @note
993 *   http://microformats.org/wiki/hcard-fr#adr_tel_email_types
994 *   http://microformats.org/wiki/hcard-fr#valeurs_sous-propri.C3.A9t.C3.A9_type
995 *   http://microformats.org/wiki/hcard-fr#Lisible_par_Humain_vs._Machine
996 *   http://microformats.org/wiki/vcard-suggestions#EMAL_Type_Definition
997 *   http://en.wikipedia.org/wiki/Email#URI_scheme_mailto:
998 *   http://www.remote.org/jochen/mail/info/address.html
999 *   http://en.wikipedia.org/wiki/X.400#Addressing
1000 */
1001function association_formater_emails($id_objets, $objet='auteur', $html_span='div', $sep=' ') {
1002        $id_objets = association_recuperer_liste($id_objets, FALSE);
1003        if ($objet) { // ancien comportement : ce sont les id_objet qui sont transmis
1004                $emails_array = array(); // initialisation du tableau des donnees
1005                foreach ($id_objets as $id_objet) { // prepare la structure du tableau renvoye
1006                        $emails_array[$id_objet] = array();
1007                }
1008                if ( $objet=='auteur' ) { // on commence par recuperer les emails de la table spip_auteurs
1009                        $query = sql_select("id_auteur, email, CONCAT('0-', id_auteur) AS id_email, '' AS titre, '' AS type", 'spip_auteurs', sql_in('id_auteur', $id_objets)." AND email <> ''"); // on peut prendre comme titre le champ "nom" qui peut etre different du nom de membre affiche (c'est un pseudo) mais ce n'est pas forcement pertinent ; on peut reprendre le champ "email" aussi mais cela empeche le reformatage automatique et on a une longue colonne disgracieuse...
1010                        while ($auteur_info = sql_fetch($query))
1011                                $emails_array[$auteur_info['id_auteur']][] = $auteur_info;
1012                        sql_free($query);
1013                }
1014                $trouver_table = charger_fonction('trouver_table', 'base');
1015                if ( $trouver_table('spip_emails') && $trouver_table('spip_emails_liens') ) { // le plugin "Coordonnees" est installe (active ou pas)
1016                        $query = sql_select('l.id_objet, l.type, e.*','spip_emails AS e INNER JOIN spip_emails_liens AS l ON l.id_email=e.id_email', sql_in('l.id_objet', $id_objets)." AND l.objet='$objet' ");
1017                        while ($data = sql_fetch($query)) { // on recupere tous les numeros dans un tableau de tableaux
1018                                $emails_array[$data['id_objet']][] = $data;
1019                        }
1020                        sql_free($query);
1021                }
1022        } else { // on a deja la liste des emails !
1023                $emails_array = $id_objets;
1024        }
1025        $emails_string = array();  // initialisation du tableau renvoye
1026        foreach ($emails_array as $id_objet => $courriels) {  // on cree la liste de chaines de courriels
1027                $emails_string[$id_objet] = ' '; // initialisation de la chaine renvoyee
1028                foreach ($courriels as $courriel) { // formater chaque mel
1029                        $href = FALSE;
1030                        if ( !is_array($courriel) ) {
1031                                $courriel['email'] = $courriel;
1032                        }
1033                        if ($html_span) { // balisage HTML avec microformat
1034                                $emails_string[$id_objet] = "<$html_span class='email'>". association_formater_typecoord('mel', $courriel['type']);
1035                                if ( !$courriel['type'] || stripos($courriel['type'], 'internet')!==FALSE )
1036                                        $href = TRUE;
1037                                $emails_string[$id_objet] .= ($href?("<a title='". _T('asso:ecrire_a') ." $courriel[email]' href='mailto:$courriel[email]'"):'<span') ." class='value'>";
1038                                unset($courriel['type']); // ne devrait plus etre traite par le modele
1039                                unset($courriel['id_objet']); // ne devrait plus etre traite par le modele
1040                                unset($courriel['id_email']); // ne devrait pas etre utilise par le modele
1041                                $courriel['email'] = ( $courriel['titre'] ? $courriel['titre'] : ucwords(str_replace('@', ' ['._T('perso:at').'] ', $courriel['email'])) ); // on affiche le titre si present sinon la valeur
1042                        }
1043                        $emails_string[$id_objet] .= $courriel['email']. ($html_span?('</'.($href?'a':'span')."></$html_span>\n"):'');
1044                }
1045                $emails_string[$id_objet] = $emails_string[$id_objet].$sep;
1046        }
1047        return $emails_string;
1048}
1049
1050/**
1051 * Affichage micro-formate de liste d'adresses electroniques
1052 *
1053 * @param array $id_objets
1054 *   Liste des (listes de) URLs a formater, ou
1055 *   liste des ID dont on doit formater les URLs (voir parametre suivant)
1056 * @param string $objet
1057 *   Indique le type d'objet dont les ID sont passes afin de recuperer les
1058 *   numeros associes a ces objets. Quand rien n'est indique c'est que c'est la
1059 *   liste de liste des numeros qui est directement fournie.
1060 *   (ceci est prevu pour etendre facilement l'usage de la fonction si necessaire,
1061 *   vaut "auteur" par defaut)
1062 * @param bool $a
1063 *   Active (si oui) la creation d'un lien cliquable avec la classe "url" ou renvoit juste (si faux) l'adresse brute
1064 * @param string $sep
1065 *   Separateur entre les adresse.
1066 *   Par defaut l'espace.
1067 * @return array $urls_string
1068 *   Liste des liens formates en HTML.
1069 * @note
1070 *   http://microformats.org/wiki/vcard-suggestions#URL_Type_Definition
1071 * @note
1072 *   http://en.wikipedia.org/wiki/Instant_messaging#Interoperability
1073 *   http://en.wikipedia.org/wiki/Comparison_of_instant_messaging_protocols
1074 *   http://microformats.org/wiki/hcard-examples#AOL_Instant_Messenger_.28AIM.29
1075 *   http://tools.ietf.org/html/rfc4770
1076 *   http://rfc-ref.org/RFC-TEXTS/4770/kw-uri.html
1077 *   http://en.wikipedia.org/wiki/VCard#vCard_extensions
1078 *   http://en.wikipedia.org/wiki/Social_web
1079 *   http://fr.wikipedia.org/wiki/R%C3%A9seau_social#R.C3.A9seaux_sociaux_sur_Internet
1080 *   http://fr.wikipedia.org/wiki/R%C3%A9seautage_social#R.C3.A9seaux_ayant_plus_de_30_millions_d.27inscriptions
1081 *   http://fr.wikipedia.org/wiki/Uniform_Resource_Identifier
1082 *   http://fr.wikipedia.org/wiki/Hyperlien
1083 */
1084function association_formater_urls($id_objets, $objet='auteur', $a=TRUE, $sep=' ') {
1085        $id_objets = association_recuperer_liste($id_objets, FALSE);
1086        if ($objet) { // ancien comportement : ce sont les id_objet qui sont transmis
1087                $urls_array = array(); // initialisation du tableau des donnees
1088                foreach ($id_objets as $id_objet) { // prepare la structure du tableau renvoye
1089                        $urls_array[$id_objet] = array();
1090                }
1091                if ( in_array($objet, array('auteur', 'breve', 'forum', 'syndic', 'signature')) ) { // on commence par recuperer les #NOM_SITE et #URL_SITE des tables natives de SPIP (pour les breves c'est plutot #LIEN_TITRE et #LIEN_URL ! pfff...)
1092                        $query = sql_select("id_$objet, ". ($objet=='breve'?'lien_titre':'nom_site') .' AS titre, '.  ($objet=='breve'?'lien_url':'url_site') ." AS url, CONCAT('0-',id_$objet) AS id_url, 'site' AS type",
1093                        "spip_{$objet}s",
1094                        sql_in("id_$objet", $id_objets) .' AND '. ($objet=='breve'?'lien_url':'url_site'). "<>''");
1095                        while ($site = sql_fetch($query))
1096                                $urls_array[$site["id_$objet"]][] = $site;
1097                        sql_free($query);
1098                }
1099                $trouver_table = charger_fonction('trouver_table', 'base');
1100                if ( $trouver_table('spip_syndic') && $trouver_table('spip_syndic_liens') ) { // le plugin "Coordonnees" est installe (active ou pas)
1101                        $query = sql_select('l.id_syndic AS id_url, l.id_objet, l.type, s.url_site AS url, s.nom_site AS titre, s.id_syndic AS id_url','spip_syndic AS s INNER JOIN spip_syndic_liens AS l ON l.id_syndic=s.id_syndic', sql_in('l.id_objet', $id_objets)." AND l.objet='$objet' ");
1102                        while ($data = sql_fetch($query)) { // on recupere tous les sites lies dans un tableau de tableaux
1103                                $urls_array[$data['id_objet']][] = $data;
1104                        }
1105                        sql_free($query);
1106                }
1107/*
1108                if ( $trouver_table('spip_sites') && $trouver_table('spip_sites_liens') ) { // le plugin "Coordonnees" est installe (active ou pas)
1109                        $query = sql_select('l.id_site AS id_url, l.id_objet, l.type, s.*','spip_sites AS s INNER JOIN spip_sites_liens AS l ON l.id_site=s.id_site', sql_in('l.id_objet', $id_objets)." AND l.objet='$objet' ");
1110                        while ($data = sql_fetch($query)) { // on recupere tous les sites lies dans un tableau de tableaux
1111                                $urls_array[$data['id_objet']][] = $data;
1112                        }
1113                        sql_free($query);
1114                }
1115                if ( $trouver_table('spip_ims') && $trouver_table('spip_ims_liens') ) { // le plugin "Coordonnees" est installe (active ou pas)
1116                        $query = sql_select("l.id_objet, l.type, m.id_im AS id_url, m.identifiant AS titre,  CONCAT(CONCAT(t.url_debut,m.titre),t.url_fin) AS url ",
1117                        'spip_ims AS m INNER JOIN spip_ims_liens AS l ON l.id_im=m.id_im INNER JOIN spip_ims_types AS t ON l.type=t.type',
1118                        sql_in('l.id_objet', $id_objets)." AND l.objet='$objet' ");
1119                        while ($data = sql_fetch($query)) { // on recupere tous les sites lies dans un tableau de tableaux
1120                                $urls_array[$data['id_objet']][] = $data;
1121                        }
1122                        sql_free($query);
1123                }
1124*/
1125        } else { // on a deja la liste des URLs !
1126                $urls_array = $id_objets;
1127        }
1128        $urls_string = array();  // initialisation du tableau renvoye
1129        foreach ($urls_array as $id_objet => $urls) { // on le transforme en liste de chaines formatees
1130                $urls_string[$id_objet] = ''; // initialisation de la chaine renvoyee
1131                foreach ($urls as $lien) { // il y a la(s) URL(s)
1132                        if ( !is_array($lien) ) {
1133                                $lien['url'] = $lien;
1134                        }
1135                        if ( $lien['type'] && $lien['titre'] && !$lien['url'] ) { // pas d'URL ??? on va tenter d'utiliser l'identifiant de messagerie
1136                                $lien['url'] = $lien['type'].':'. htmlspecialchars($lien['titre']) ; // on presume que le "type" est le protocole et que le "titre" est le reste...
1137                        }
1138                        if ($a) { // balisage HTML avec microformat
1139                                $urls_string[$id_objet] = "<a class='url' href='$lien[url]' id='$lien[id_url]'>". association_formater_typecoord('url', $lien['type']);
1140                                unset($lien['type']); // ne devrait plus etre traite par le modele
1141                                unset($lien['id_objet']); // ne devrait plus etre traite par le modele
1142                                unset($lien['id_url']); // ne devrait pas etre utilise par le modele
1143                                $urls_string[$id_objet] = $urls_string[$id_objet]. ($lien['titre']?$lien['titre']:$lien['url']); // on affiche le titre si present sinon la valeur
1144                        } else
1145                                $urls_string[$id_objet] .= $lien['url'];
1146                        $urls_string .= ($a?'</a>':'') .$sep;
1147                }
1148        }
1149        return $urls_string;
1150}
1151
1152/** @} */
1153
1154
1155/*****************************************
1156 * @defgroup association_recuperer
1157 * Transforme un champ de formulaire en vue de son insertion en base de donnees.
1158 * S'utilise donc sur un champ passe par le @ref association_verifier correspondant.
1159 * Assure donc un bon enregistrement et la restitution par le @ref association_formater correspondant.
1160 *
1161 * @param string $valeur
1162 *   Nom a recuperer (par GET ou POST ou Cookie) ...ou la valeur directement
1163 * @param bool $req
1164 *   Indique s'il s'agit du nom (vrai --par defaut) ou pas (faux, donc la valeur)
1165 *
1166** @{ */
1167
1168/**
1169 * @return string $valeur
1170 *   Date au format ISO
1171 */
1172function association_recuperer_date($valeur, $req=TRUE) {
1173        $valeur = ($req?_request($valeur):$valeur);
1174        if ( $valeur ) {
1175                $valeur = preg_replace('/\D/', '-', $valeur, 2); // la limitation a 2 separateurs permet de ne transformer que la partie "date" s'il s'agit d'un "datetime" par exemple.
1176        }
1177        return $valeur;
1178}
1179
1180/**
1181 * @return float $valeur
1182 *   Nombre decimal
1183 * @note
1184 *   Bien qu'il s'agisse en fait de s'assurer que la valeur est un flottant, la fonction s'appelle _montant car elle est utilisee surtout pour les montants.
1185 */
1186function association_recuperer_montant($valeur, $req=TRUE) {
1187        $valeur = ($req?_request($valeur):$valeur);
1188        if ( $valeur ) {
1189                setlocale(LC_NUMERIC, utiliser_langue_visiteur() );
1190                $locale = localeconv(); // recuperer les parametres regionnaux
1191                $valeur = str_replace($locale['thousands_sep'], '', $valeur); // suppprime les separateurs de milliers
1192                $valeur = str_replace($locale['decimal_point'], '.', $valeur); // remplacer le separateur decimal par le point
1193                $valeur = floatval($valeur);
1194        }
1195        return floatval($valeur);
1196}
1197
1198/**
1199 * @return int $valeur
1200 *   Nombre entier
1201 * @note
1202 *   Bien qu'il s'agisse en fait de s'assurer que la valeur est un entier, la fonction s'appelle _id car elle est utilisee surtout pour les identifiants de table.
1203 */
1204function association_recuperer_entier($valeur, $req=TRUE) {
1205        $valeur = ($req?_request($valeur):$valeur);
1206        return intval($valeur);
1207}
1208
1209/**
1210 * @param string  $sep
1211 *   Separateur a utiliser pour concatener les elements du tableau
1212 * @return array|string $valeur
1213 *   Liste de valeurs
1214 * @note
1215 *   ...
1216 */
1217function association_recuperer_liste($valeur, $req=FALSE, $sep='') {
1218        $valeur = ($req?_request($valeur):$valeur);
1219        if ( !is_array($valeur) )
1220                if ( is_scalar($valeur) ) // chaine ou nombre
1221                        $valeur = array($valeur);
1222                else // objet ou ressource ou autre
1223                        $valeur = array();
1224        return ($sep ? implode($sep, $valeur) : $valeur);
1225//      return ($sep ? sql_in($sep, $valeur) : $valeur);
1226}
1227
1228/** @} */
1229
1230
1231/*****************************************
1232 * @defgroup association_verifier
1233 * Verification du format de la valeur d'un champ de formulaire.
1234 * Permet d'appeler @ref association_recupere equivalent sur ce champ...
1235 *
1236 * @param string $valeur
1237 *   Nom a recuperer (par GET ou POST ou Cookie) ...ou la valeur directement
1238 * @param bool $rex
1239 *   Indique si la verification est plus lache (vrai) ou pas (faux --par defaut)
1240 *   [le nom de la variable signifie "RElaXed check"]
1241 * @param bool $req
1242 *   Indique s'il s'agit du nom (vrai --par defaut) ou pas (faux, donc la valeur)
1243 *   [le nom de la variable signifie "by REQuest"]
1244 * @return string
1245 *   Message d'erreur... (donc chaine vide si OK)
1246 *
1247** @{ */
1248
1249/**
1250 * S'assurer que la valeur saisie est une chaine de date valide
1251 */
1252function association_verifier_date($valeur, $rex=FALSE, $req=TRUE) {
1253        $date = $req ? _request($valeur) : $valeur;
1254        if ( $rex && ($date=='0000-00-00' || !$date) )
1255                return '';
1256        if (!preg_match('/^\d{4}\D\d{2}\D\d{2}$/', $date)) // annee sur 4 chiffres ; mois sur 2 chiffres ; jour sur 2 chiffres ; separateur est caractere non numerique quelconque...
1257#       if (!preg_match('/^\d{4}\D(\d|1[0-2])\D([1-9]|0[1-9]|[12]\d|3[01])$/', $date)) // annee sur 4 chiffres ; mois sur 1 ou 2 chiffres entre 1 et 12 ; jour sur 1 ou 2 chiffres eentre 1 et 31 ; separateur est n'importe quel caractere ne representant pas un chiffre arabe de la notation decimale standard...
1258                return _T('asso:erreur_format_date', array('date'=>$date) ); // ...c'est un petit plus non documente (la documentation et le message d'erreur stipulent AAAA-MM-JJ : mois et jours toujours sur deux chiffres avec donc zero avant si inferieur a 10, et separateur est tiret)
1259        list($annee, $mois, $jour) = preg_split('/\D/', $date);
1260        if (!checkdate($mois, $jour, $annee)) // la date doit etre valide : pas de 30 fevrier ou de 31 novembre par exemple.
1261                return _T('asso:erreur_valeur_date', array('date'=>$date) );
1262        return '';
1263}
1264
1265/**
1266 * S'assurer que la valeur saisie est un flottant positif
1267 */
1268function association_verifier_montant($valeur, $req=TRUE) {
1269        if (association_recuperer_montant($valeur,$req)<0)
1270                return _T('asso:erreur_montant');
1271        else
1272                return '';
1273}
1274
1275/**
1276 * S'assurer que l'entier saisie correspond bien a un id_auteur
1277 * de la table spip_asso_membres (par defaut) ou spip_auteurs (si on elargi a tous
1278 * --ceci permet d'editer des membres effaces tant qu'ils sont references par SPIP)
1279 */
1280function association_verifier_membre($valeur, $rex=FALSE, $req=TRUE) {
1281        $id_auteur = intval($req?_request($valeur):$valeur);
1282        if ($id_auteur) {
1283                if ( sql_countsel('spip_'.($rex?'auteurs':'asso_membres'), "id_auteur=$id_auteur")==0 ) {
1284                        return _T('asso:erreur_id_adherent');
1285                }
1286        } else
1287                return '';
1288}
1289
1290/**
1291 * S'assurer que la somme des ventilations par destinations comptables correspond
1292 * au montant de l'operation.
1293 * le parametre d'entree est le montant total attendu, les montants des destinations
1294 * sont recuperes directement dans $_POST
1295 */
1296function association_verifier_destinations($valeur, $req=TRUE) {
1297        if (!$GLOBALS['association_metas']['destinations']) return FALSE;
1298
1299        // verifier si besoin que le montant des destinations
1300        // correspond bien au montant de l'operation
1301        $montant_attendu = floatval($req?_request($valeur):$valeur);
1302        $err = '';
1303        $toutesDestinationsIds = _request('id_dest');
1304        $toutesDestinationsMontants = _request('montant_dest');
1305        $total_destination = 0;
1306        $id_inserted = array();
1307        if (count($toutesDestinationsIds)>1) { // on a plusieurs destinations
1308                foreach ($toutesDestinationsIds as $id => $id_destination) { 
1309                  // on verifie qu'il n'y a pas plusieurs fois
1310                  // la meme destination, tout en recalculant le total
1311                        if (!array_key_exists($id_destination,$id_inserted)) {
1312                                $id_inserted[$id_destination] = 0;
1313                        } else {
1314                                $err = _T('asso:erreur_destination_dupliquee');
1315                        }
1316                        $total_destination += association_recuperer_montant($toutesDestinationsMontants[$id], FALSE); // les montants sont dans un autre tableau aux meme cles
1317                }
1318                if ( $montant_attendu!=$total_destination ) { // on verifie que la somme des montants des destinations correspond au montant attendu
1319                                $err .= _T('asso:erreur_montant_destination');
1320                }
1321        } else { // une seule destination, le montant peut ne pas avoir ete precise, dans ce cas pas de verif, c'est le montant attendu qui sera entre dans la base
1322                if ($toutesDestinationsMontants[1]) { // quand on a une seule destination, l'id dans les tableaux est forcement 1 par contruction de l'editeur
1323                        if ( $montant_attendu!=association_recuperer_montant($toutesDestinationsMontants[1], FALSE) ) { // on verifie que le montant indique correspond au montant attendu
1324                          $err = _T('asso:erreur_montant_destination');
1325                        }
1326                }
1327        }
1328        return $err;
1329}
1330
1331/** @} */
1332
1333
1334/*****************************************
1335 * @defgroup association_selectionner
1336 * Selecteur HTML (liste deroulante) servant a filtrer le listing affiche en milieu de page
1337 *
1338 * @param string $exec
1339 *   Nom du fichier de l'espace prive auquel le formulaire sera soumis.
1340 *   Si present, le formulaire complet (balise-HTML "FORM") est genere.
1341 *   Si absent (par defaut), seul le selecteur (et le code supplementaire fourni
1342 *   par $plus) est(sont) renvoye(s).
1343 * @param string $plus
1344 *   Source HTML rajoute a la suite.
1345 *   (utile si on genere tout le formulaire avec des champs caches)
1346 * @return string $res
1347 *   Code HTML du selecteur (ou du formulaire complet si $exec est indique)
1348 *
1349** @{ */
1350
1351/**
1352 * @name association_selectionner_<liste>
1353 * cas general de :
1354 *
1355 * @param int $sel
1356 *   ID selectionne : conserve la valeur selectionnee
1357 */
1358//@{
1359
1360/**
1361 * Selecteur d'exercice comptable
1362 */
1363function association_selectionner_exercice($sel='', $exec='', $plus='') {
1364    $res = '<select name ="exercice" onchange="form.submit()">';
1365#    $res .= '<option value="0" ';
1366#       $res .= (!$el?' selected="selected"':'');
1367#    $res .= '>'. _L("choisir l'exercice ?") .'</option>';
1368    $sql = sql_select('id_exercice, intitule', 'spip_asso_exercices', '', 'intitule DESC');
1369    while ($val = sql_fetch($sql)) {
1370                $res .= '<option value="'.$val['id_exercice'].'" ';
1371                $res .= ($sel==$val['id_exercice']?' selected="selected"':'');
1372                $res .= '>'.$val['intitule'].'</option>';
1373    }
1374    sql_free($sql);
1375    $res .= '</select>'.$plus;
1376    return $exec ? generer_form_ecrire($exec, $res.'<noscript><input type="submit" value="'._T('asso:bouton_lister').'" /></noscript>') : $res;
1377}
1378
1379/**
1380 * Selecteur de destination comptable
1381 */
1382function association_selectionner_destination($sel='', $exec='', $plus='') {
1383    if ( !$GLOBALS['association_metas']['destinations'])
1384                return ''; // on n'affiche le selecteur que si l'utilisation des destinations est activee en configuration
1385   $res = '<select name ="destination" onchange="form.submit()">';
1386    $res .= '<option value="0" ';
1387        $res .= (!$sel?' selected="selected"':'');
1388    $res .= '>'. _T('asso:toutes_destinations') .'</option>';
1389    $intitule_destinations = array();
1390    $sql = sql_select('id_destination, intitule', 'spip_asso_destination','', 'intitule DESC');
1391    while ($val = sql_fetch($sql)) {
1392                $res .= '<option value="'.$val['id_destination'].'" ';
1393                $res .= ($sel==$val['id_destination']?' selected="selected"':'');
1394                $res .= '>'.$val['intitule'].'</option>';
1395    }
1396    sql_free($sql);
1397    $res .= '</select>'.$plus;
1398        return $exec ? generer_form_ecrire($exec, $res.'<noscript><input type="submit" value="'._T('asso:bouton_lister').'" /></noscript>') : $res;
1399}
1400
1401/**
1402 * Selecteur de grouoe de membres
1403 */
1404function association_selectionner_groupe($sel='', $exec='', $plus='') {
1405    $sql = sql_select('id_groupe, nom', 'spip_asso_groupes', 'id_groupe>=100', '', 'nom');  // on ne prend en consideration que les groupe d'id >= 100, les autres sont reserves a la gestion des autorisations
1406    if ( !$sql || !sql_count($sql) )
1407                return '';  // ne proposer que s'il y a des groupes definis
1408        $res = '<select name="groupe" onchange="form.submit()">';
1409        $res .= '<option value=""';
1410        $res .= (!$sel?' selected="selected"':'');
1411    $res .= '>'. _T('asso:tous_les_groupes') .'</option>';
1412        while ($val = sql_fetch($sql)) {
1413                $res .= '<option value="'.$val['id_groupe'].'"';
1414                $res .= ($sel==$val['id_groupe']?' selected="selected"':'');
1415                $res .= '>'.$val['nom'].'</option>';
1416        }
1417        sql_free($sql);
1418        $res .= '</select>'.$plus;
1419        return $exec ? generer_form_ecrire($exec, $res.'<noscript><input type="submit" value="'. _T('asso:bouton_lister') .'" /></noscript>') : $res;
1420}
1421
1422/**
1423 * Selecteur de statut de membres
1424 *
1425 * @note
1426 *   Idem instituer_statut_interne_ici
1427 *   Idem instituer_adherent_ici
1428 */
1429function association_selectionner_statut($sel='', $exec='', $plus='') {
1430    $res = "<select id='statut_interne' name='statut_interne' onchange='form.submit()'>";
1431#    $res .= '<option value="tous"';
1432#    $res .= (($sel=='tous' || $sel=='%')?' selected="selected"':'');
1433#    $res .= '>'. _T('asso:entete_tous') .'</option>';
1434    $res .= '<option value=""';
1435    $res .= (($sel=='defaut' || $sel=='')?' selected="selected"':'');
1436    $res .= '>'. _T('asso:actifs') ."</option>\n";
1437    foreach ($GLOBALS['association_liste_des_statuts'] as $statut) {
1438                $res .= '<option value="'.$statut.'"'
1439                . ($sel==$statut?' selected="selected"':'')
1440                . '> '
1441                . _T('asso:adherent_entete_statut_'.$statut)
1442                . "</option>\n";
1443        }
1444        $res .= '</select>'.$plus;
1445    return $exec ? generer_form_ecrire($exec, $res.'<noscript><input type="submit" value="'. _T('asso:bouton_lister') .'" /></noscript>') : $res;
1446}
1447
1448/* Meme fonction que la precedente, mais en donnat l'ID */
1449
1450function association_selectionner_statut_id($sel, $id) {
1451        $res = association_selectionner_statut($sel);
1452        return str_replace("id='statut_interne'", "id='$id'", $res);
1453}
1454
1455/**
1456 * Zone de saisie de numero de membre
1457 */
1458function association_selectionner_id($sel='', $exec='', $plus='') {
1459    $res = '<input type="text" name="id" onfocus=\'this.value=""\' size="5"  value="'. ($sel?$sel:_T('asso:entete_id')) .'" />'.$plus;
1460    return $exec ? generer_form_ecrire($exec, $res.'<noscript><input type="submit" value="'. _T('asso:bouton_lister') .'" /></noscript>') : $res;
1461}
1462
1463//@}
1464
1465/**
1466 * @name association_selectionner_<liste>
1467 * cas general de :
1468 *
1469 * @param string $table
1470 *   Nom (sans prefixe "spip_") de la table concernee
1471 * @param bool $lst
1472 *   Type : liste de selection (vrai) ou liens (faux)
1473 */
1474//@{
1475
1476/**
1477 * Selecteur d'annee parmi celles disponibles dans une table donnee
1478 *
1479 * @param string $annee
1480 *   Annee selectionnee. (annee courante par defaut)
1481 * @param string $champ
1482 *   Nom (sans prefixe "date_") du champ contenant les annees recherchees
1483 *
1484 */
1485function association_selectionner_annee($annee='', $table, $champ, $exec='', $plus='', $lst=TRUE) {
1486    if ($exec) {
1487                $res = '<form method="post" action="'. generer_url_ecrire($exec) .'"><div>';
1488                $res .= '<input type="hidden" name="exec" value="'.$exec.'" />';
1489    } else {
1490                $res = '';
1491    }
1492    $pager = '';
1493    if ( !$annee ) // annee non precisee (ou valant 0)
1494                $annee = date('Y'); // on prend l'annee courante
1495    $res .= '<select name ="annee" onchange="form.submit()">';
1496    $an_max = sql_getfetsel("MAX(DATE_FORMAT(date_$champ, '%Y')) AS an_max", "spip_$table", '');
1497    $an_min = sql_getfetsel("MIN(DATE_FORMAT(date_$champ, '%Y')) AS an_min", "spip_$table", '');
1498    if ( $annee>$an_max || $annee<$an_min ) // si l'annee (courante) n'est pas disponible dans la liste deroulante on est mal positionne et le changement de valeur n'est pas top
1499                $res .= '<option value="'.$annee.'" selected="selected">'.$annee.'</option>';
1500    $sql = sql_select("DATE_FORMAT(date_$champ, '%Y') AS annee", "spip_$table",'', 'annee DESC', 'annee');
1501    while ($val = sql_fetch($sql)) {
1502                $res .= '<option value="'.$val['annee'].'"';
1503                if ($annee==$val['annee']) {
1504                        $res .= ' selected="selected"';
1505                        $pager .= "\n<strong>$val[annee]</strong>";
1506                } else {
1507                        $pager .= ' <a href="'. generer_url_ecrire($exec, '&annee='.$val['annee']) .'">'.$val['annee']."</a>\n";
1508                }
1509                $res .= '>'.$val['annee'].'</option>';
1510    }
1511    $res .= '</select>'.$plus;
1512    sql_free($sql);
1513    if ($exec) {
1514                $res .= '<noscript><input type="submit" value="'. _T('asso:bouton_lister') .'" /></noscript>';
1515                $res .= '</div></form>';
1516    }
1517    return ($lst?$res:$pager.$plus);
1518}
1519
1520/**
1521 * Selecteur d'initiale parmi celles disponibles dans une table donnee
1522 *
1523 * @param string $lettre
1524 *   Initiale selectionnee. (aucune par defaut)
1525 * @param string $champ
1526 *   Nom du champ contenant les initiales recherchees
1527 *
1528 */
1529function association_selectionner_lettre($lettre='', $table, $champ, $exec='', $plus='', $lst=FALSE) {
1530    $lettre = strtoupper($lettre);
1531    if ($exec) {
1532                $res = '<form method="post" action="'. generer_url_ecrire($exec) .'"><div>';
1533                $res .= '<input type="hidden" name="exec" value="'.$exec.'" />';
1534    } else {
1535                $res = '';
1536    }
1537    $pager = '';
1538    $res .= '<select name ="lettre" onchange="form.submit()">';
1539        $res .= '<option value=""';
1540        $res .= ((!$lettre||$lettre=='%')?' selected="selected"':'');
1541        $res .='>'. _T('asso:entete_tous') .'</option>';
1542    $sql = sql_select("UPPER( LEFT( $champ, 1 ) ) AS init", "spip_$table", '',  'init ASC', "$champ"); // LEFT(field, n) ==  SUBSTRING(field, 1, n)
1543    while ($val = sql_fetch($sql)) {
1544                $res .= '<option value="'.$val['init'].'"';
1545                if ($lettre==$val['init']) {
1546                        $res .= ' selected="selected"';
1547                        $pager .= "\n<strong>$lettre</strong>";
1548                } else {
1549                        $pager .= ' <a href="'. generer_url_ecrire($exec, 'lettre='.$val['init']) .'">'.$val['init'].'</a>';
1550                }
1551                $res .= '>'.$val['init'].'</option>';
1552    }
1553    sql_free($sql);
1554    $res .= '</select>'.$plus;
1555    if ($exec) {
1556                $res .= '<noscript><input type="submit" value="'. _T('asso:bouton_lister') .'" /></noscript>';
1557                $res .= '</div></form>';
1558    }
1559    if ( !$lettre || $lettre=='%' ) {
1560                $pager .= ' <strong>'. _T('asso:entete_tous') .'</strong>';
1561        } else {
1562                $pager .= ' <a href="'. generer_url_ecrire($exec) .'">'. _T('asso:entete_tous') .'</a>';
1563        }
1564    return ($lst?$res:($pager.$plus));
1565}
1566
1567/**
1568 * Selecteur d'exercice ou d'annee parmi celles disponibles dans une table donnee
1569 *
1570 * @param int $periode
1571 *   Annee ou exercice selectionnee.
1572 *   (dernier exercice ou annee courante par defaut)
1573 * @param string $champ
1574 *   Nom (sans prefixe "date_") du champ contenant les annees recherchees
1575 *
1576 * @see association_selectionner_annee
1577 * @see association_selectionner_exercice
1578 */
1579function association_selectionner_periode($periode, $table, $champ) {
1580        return $GLOBALS['association_metas']['exercices'] ? association_selectionner_exercice($periode) : association_selectionner_annee($periode, $table, $champ) ;
1581}
1582
1583//@}
1584
1585/**
1586 * Selecteur de destinations comptables
1587 *
1588 * @param array $sel
1589 *   Liste des ID de destination selectionnes
1590 * @param bool $lst
1591 *   Indique s'il faut afficher le resultat sous forme d'une liste de selections
1592 *   multiples (vrai) ou sous forme de cases a cocher (faux)
1593 * @note
1594 *   Il s'agit d'un selecteur maintenu par compatibilite (usage uniquement dans
1595 *   exec/bilan.php actuellement) et ne devrait plus etre utilise a l'avenir
1596 */
1597function association_selectionner_destinations($sel='', $exec='', $plus='', $lst=FALSE) {
1598    if (!$GLOBALS['association_metas']['destinations'])
1599                return FALSE;
1600    $res1 = '<select name ="destinations[]" multiple="multiple" onchange="form.submit()">';
1601    $res2 = '';
1602    $res1 .= '<option value="0" ';
1603    $res2 .= '<div class="choix"><input type="checkbox" name ="destinations[]" value="0" id="destination_0"';
1604    if ( !(array_search(0, $sel)===FALSE) ) {
1605                $res1 .= ' selected="selected"';
1606                $res2 .= ' checked="checked"';
1607    }
1608    $res1 .= '>'. _T('asso:toutes_destinations') .'</option><option disabled="disabled"></option>';
1609    $res2 .= ' /><label for="destination_0">'._T('asso:toutes_destinations').'</label></div>';
1610    $res2 .= '<div class="choix"><hr /></div>';
1611    $intitule_destinations = array();
1612    $sql = sql_select('id_destination, intitule', 'spip_asso_destination','', 'intitule DESC');
1613    while ($val = sql_fetch($sql)) {
1614                $res1 .= '<option value="'.$val['id_destination'].'"';
1615                $res2 .= '<div class="choix"><input type="checkbox" name ="destinations[]" value="'.$val['id_destination'].'" id="destination_'.$val['id_destination'].'"';
1616                if ( !(array_search($val['id_destination'], $sel)===FALSE) ) {
1617                        $res1 .= ' selected="selected"';
1618                        $res2 .= ' checked="checked"';
1619                }
1620                $res1 .= '>'.$val['intitule'].'</option>';
1621                $res2 .= ' /><label for="destination_'.$val['id_destination'].'">'.$val['intitule'].'</label></div>';
1622                $intitule_destinations[$val['id_destination']] = $val['intitule'];
1623    }
1624        sql_free($sql);
1625    $res1 .= '</select>'.$plus;
1626    $res2 .= ''.$plus;
1627    $res = ($lst?$res1:$res2);
1628        return $exec ? generer_form_ecrire($exec, $res.'<input type="submit" value="'. _T('asso:bouton_lister') .'" />') : $res;
1629}
1630
1631/**
1632 * Selecteur de sous-pagination
1633 *
1634 * @param int|array $pages
1635 *   Nombre total de pages ou
1636 *   Liste des elements a passer a "sql_countsel"
1637 * @param string $exec
1638 *   Nom du fichier appelant
1639 * @param string $params
1640 *   Autres informations passees par l'URL
1641 * @param int $debut
1642 *   Numero du premier enregistrement (si $req est a faux)
1643 *   Nom du champ contenant ce numero (si $req est a vrai)
1644 * @param bool $req
1645 * @param bool $tbl
1646 * @return string $res
1647 *   HTML du bandeau de pagination
1648 */
1649function association_selectionner_souspage($pages, $exec='', $arg=array(), $tbl=TRUE, $debut='debut', $req=TRUE) {
1650        $res = ($tbl?"<table width='100%' class='asso_tablo_filtres'><tr>\n":'') .'<td align="left">';
1651        if ( is_array($pages) ) {
1652                $nbr_pages = ceil(call_user_func_array('sql_countsel',$pages)/_ASSOCIASPIP_LIMITE_SOUSPAGE); // ceil() ou intval()+1 ?
1653        } else {
1654                $nbr_pages = intval($pages);
1655        }
1656        if ( $nbr_pages>1 ) {
1657                $debut = ($req?_request($debut):$debut);
1658                $exec = ($exec?$exec:_request($exec));
1659                if (!is_array($arg)) $arg = array($arg);
1660                for ($i=0; $i<$nbr_pages; $i++) {
1661                        $position = $i*_ASSOCIASPIP_LIMITE_SOUSPAGE;
1662                        if ($position==$debut) { // page courante
1663                                $res .= "\n<strong>".$position.' </strong> ';
1664                        } else { // autre page
1665                                $arg['debut']= 'debut='.$position;
1666                                $h = generer_url_ecrire($exec, join('&', $arg));
1667                                $res .= "<a href='$h'>$position</a>\n";
1668                        }
1669                }
1670        }
1671        $res .= "</td>\n";
1672        return $res. ($tbl?"\n</tr></table>":'');
1673}
1674
1675/** @} */
1676
1677
1678/*****************************************
1679 * @defgroup generer_url
1680 * Raccourcis SPIP de lien rajoutes par ce plugin
1681 *
1682 * Les tables ayant deux prefixes ("spip_asso_"),
1683 * le raccourci "x" implique de declarer le raccourci "asso_x"
1684 *
1685** @{ */
1686
1687/*c
1688 * [->asso_donN] = /?exec=edit_don&id=N
1689 */
1690function generer_url_asso_don($id, $param='', $ancre='') {
1691        return  generer_url_ecrire('edit_don', 'id='.intval($id));
1692}
1693/*c
1694 * [->donN] = [->asso_dontN]
1695 */
1696function generer_url_don($id, $param='', $ancre='') {
1697        return  array('asso_don', $id);
1698}
1699
1700/*c
1701 * [->asso_membreN] = /?exec=adherent&id=N
1702 */
1703function generer_url_asso_membre($id, $param='', $ancre='') {
1704        return  generer_url_ecrire('adherent', 'id='.intval($id));
1705}
1706/*c
1707 * [->membreN] = [->asso_membreN]
1708 */
1709function generer_url_membre($id, $param='', $ancre='') {
1710        return  array('asso_membre', $id);
1711}
1712
1713/*c
1714 * [->asso_venteN] = /?exec=edit_vente&id=N
1715 */
1716function generer_url_asso_vente($id, $param='', $ancre='') {
1717        return  generer_url_ecrire('edit_vente', 'id='.intval($id));
1718}
1719/*c
1720 * [->venteN] = [->asso_venteN]
1721 */
1722function generer_url_vente($id, $param='', $ancre='') {
1723        return  array('asso_vente', $id);
1724}
1725
1726/*c
1727 * [->asso_ressourceN] = /?exec=prets&id=N
1728 */
1729function generer_url_asso_ressource($id, $param='', $ancre='') {
1730        return  generer_url_ecrire('prets', 'id='.intval($id));
1731}
1732/*c
1733 * [->ressourceN] = [->asso_ressouceN]
1734 */
1735function generer_url_ressource($id, $param='', $ancre='') {
1736        return  array('asso_ressource', $id);
1737}
1738
1739/*c
1740 * [->asso_activiteN] = /?exec=inscrits_activite&id=N
1741 */
1742function generer_url_asso_activite($id, $param='', $ancre='') {
1743        return  generer_url_ecrire('inscrits_activite', 'id='.intval($id));
1744}
1745/*c
1746 * [->activiteN] = [->asso_activiteN]
1747 */
1748function generer_url_activite($id, $param='', $ancre='') {
1749        return  array('asso_activite', $id);
1750}
1751
1752/** @} */
1753
1754
1755/*****************************************
1756 * @defgroup association_totauxinfos
1757 * Informations de synthese, sur un objet, destinees a etre presente dans le bloc
1758 * d'infos contextuel debutant la colonne de gauche
1759 *
1760** @{ */
1761
1762/**
1763 * Rappels sur l'objet dans le bloc infos
1764 *
1765 * C'est un resume ou une petite presentation de l'objet en cours
1766 * d'edition/lecture : ces informations permettent de situer le contexte de la
1767 * page et n'apparaissent pas dans le bloc central !
1768 *
1769 * @param string $titre
1770 *   Titre affiche en gros dans le bloc.
1771 * @param string $type
1772 *   Nom du raccourci, affiche au dessus du titre.
1773 * @param int $id
1774 *   ID de l'objet, affiche au dessus du titre
1775 * @param array $DesLignes
1776 *   Tableau des lignes supplementaires a rajouter dans le bloc, sous la forme :
1777 *   'chaine_de_langue_du_titre' => "texte contenu/explication associe."
1778 * @param string $ObjetEtendu
1779 *   Nom de l'objet etendu dont on desire afficher les lignes des champs rajoutes par "Interface Champs Extras 2".
1780 *   Par defaut : rien
1781 * @return string $res
1782 *
1783 * @note
1784 *   Ce n'est pas redondant d'avoir a la fois $type et $ObjetEtendu qui peuvent
1785 *   avoir des valeurs differentes comme on peut le voir dans exec/adherent.php et exec/inscrits_activite.php !
1786 */
1787function association_totauxinfos_intro($titre, $type='', $id=0, $DesLignes=array(), $ObjetEtendu='') {
1788        $res = '';
1789        if ($type) {
1790                $res .= '<div style="text-align: center" class="verdana1 spip_x-small">'. _T('asso:titre_num', array('titre'=>_T("local:$type"), 'num'=>$id) ) .'</div>'; // presentation propre a Associaspip qui complete par un autre titre (voir ci-apres). Dans un SPIP traditionnel on aurait plutot : $res .= '<div style="font-weight: bold; text-align: center" class="verdana1 spip_xx-small">'. association_langue($type) .'<br /><span class="spip_xx-large">'.$id.'</span></div>';
1791        }
1792        $res .= '<div style="text-align: center" class="verdana1 spip_medium">'.$titre.'</div>';
1793        if ( !is_array($DesLignes) )
1794                return $res;
1795        if ( count($DesLignes) OR $ObjetEtendu )
1796                $res .= '<dl class="verdana1 spip_xx-small">';
1797        foreach ($DesLignes as $dt=>$dd) {
1798                $res .= '<dt>'. association_langue($dt) .'</dt><dd>'. propre($dd) .'</dd>'; // propre() paragraphe (rajoute <p>)... mais ce comportement peut etre change en mettant "paragrapher" a FALSE dans mes_options.php : http://www.spip.net/fr_article889.html Cette presentation-ci est propre a Associaspip ; Habituellement on a : $res .= "<div class='$dt'><strong>". association_langue($dt) ."</strong> $dd</div>";
1799        }
1800        if ($ObjetEtendu) {
1801                $champsExtras = association_trouver_iextras($ObjetEtendu, $id); // on recupere les champs extras crees manuellement (i.e. via l'interface d'edition du prive, pas ceux rajoutes par les plugins !)
1802                if ( count($champsExtras) ) {
1803                        foreach ($champsExtras as $champExtra) {
1804                                $res .= '<dt>'. $champExtra[0] .'</dt>';
1805                                $res .= '<dd>'. $champExtra[1] .'</dd>';
1806/*
1807                                if ( strstr($champExtra[1], '<div')===0 ) { // c'est dans un "DIV" superflu
1808                                        $res .= substr_replace( substr_replace($chamExtra[1], '</dd>', strrpos($chamExtra[1],'</div>'), 6), 'dd', 1, 3);
1809                                } else {
1810                                        $res .= '<dd>'. $champExtra[0] .'</dd>';
1811                                }
1812*/
1813                                $res .= '<!--dd>'. $champExtra[2] .'</dd-->'; // comparaison de controle
1814                        }
1815                }
1816        }
1817        if ( count($DesLignes) OR $ObjetEtendu )
1818                $res .= '</dl>';
1819        return $res;
1820}
1821
1822/**
1823 * Tableau presentant les chiffres de synthese de la statistique descriptive
1824 *
1825 * @param string $legende
1826 *   Titre du tableau
1827 * @param string $sql_table_asso
1828 *   La table du plugin (sans prefixe "spip_asso") sur laquelle va porter les statistique.
1829 * @param array $sql_champs
1830 *   'chaine_de_langue' (sans prefixe) => "liste, des, champs, sur, laquelle, calculer, les statistiques"
1831 * @param string $sql_criteres
1832 *   Critere(s) de selection/restriction SQL des lignes (sinon toutes)
1833 * @param int $decimales_significatives
1834 *   Nombre de decimales affichees
1835 * @param bool $avec_extrema
1836 *   Indique s'il faut afficher (vrai) ou non (faux) les valeurs extremes.
1837 *   http://fr.wikipedia.org/wiki/Crit%C3%A8res_de_position#Valeur_maximum_et_valeur_minimum
1838 *   Par defaut : non, car le tableau deborde de ce petit cadre.
1839 * @return string $res
1840 *   Table HTML avec pour chaque ligne ($sql_champs) :
1841 *   - le nom attribue au groupe de champs
1842 *   - la moyenne arithmetique <http://fr.wikipedia.org/wiki/Moyenne#Moyenne_arithm.C3.A9tique>
1843 *   - l'ecart-type <http://fr.wikipedia.org/wiki/Dispersion_statistique#.C3.89cart_type>
1844 *   - ainsi que les extrema si on le desire
1845 */
1846function association_totauxinfos_stats($legende='', $sql_table_asso, $sql_champs, $sql_criteres='1=1',$decimales_significatives=1, $avec_extrema=FALSE) {
1847        if (!is_array($sql_champs) || !$sql_table_asso)
1848                return FALSE;
1849        $res = '<table width="100%" class="asso_infos"><caption>'
1850        . _T('asso:totaux_moyens', array('de_par'=>_T("local:$legende")))
1851        . "</caption>\n<thead>"
1852        . "\n<tr class='row_first'>\n<th>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>"
1853        . '<th title="'. _T('entete_stats_moy') .'">'
1854        . '<span style="text-decoration:overline;">X</span>' . "</th>\n"
1855        . "<th title='". _T('entete_stats_mea') ."'>&sigma;</th>\n"; 
1856        // σ &sigma; &#963; &#x3C3;
1857        if ($avec_extrema) {
1858                $res .= '<th title="'. _T('entete_stats_min') .'">[&lt;</th>';
1859                $res .= '<th title="'. _T('entete_stats_max') .'">&gt;]</th>';
1860        }
1861        $res .= "</tr>\n";
1862        $res .= '</thead><tbody>';
1863        $compteur = 0;
1864        foreach ($sql_champs as $libelle=>$champs) {
1865                $stats = sql_fetsel("AVG($champs) AS valMoy, STDDEV($champs) AS ekrTyp, MIN($champs) AS valMin, MAX($champs) AS valMax ", "spip_asso_$sql_table_asso", $sql_criteres);
1866                $res .= '<tr class="'. ($compteur%2?'row_odd':'row_even') .'">';
1867                $res .= "\n<td class='text'>". association_langue((is_numeric($libelle)?$champs:$libelle)) ."</td>\n";
1868                $res .= '<td class="'.($decimales_significatives?'decimal':'integer').'">'. association_formater_nombre($stats['valMoy'],$decimales_significatives) ."</td>\n";
1869                $res .= '<td class="'.($decimales_significatives?'decimal':'integer').'">'. association_formater_nombre($stats['ekrTyp'],$decimales_significatives) ."</td>\n";
1870                if ($avec_extrema) {
1871                        $res .= '<td class="'.($decimales_significatives?'decimal':'integer').'">'. association_formater_nombre($stats['valMin'],$decimales_significatives) ."</td>\n";
1872                        $res .= '<td class="'.($decimales_significatives?'decimal':'integer').'">'. association_formater_nombre($stats['valMax'],$decimales_significatives) ."</td>\n";
1873                }
1874                $res .= '</tr>';
1875                $compteur++;
1876        }
1877        $res .= '</tbody></table>';
1878        return $res;
1879}
1880
1881/**
1882 * Tableau des decomptes statistiques dans le bloc infos
1883 *
1884 * @param string $legende
1885 *   Complement du titre du tableau
1886 * @param array $lignes
1887 *   'classe_unique_css_de_la_ligne' => array( 'chaine_de_langue', effectif_occurence, "texte libre place avant la chaine de langue", "texte libre place apres la chaine de langue")
1888 * @param int $decimales_significatives
1889 *   Nombre de decimales affichees
1890 * @return string $res
1891 *   Table HTML de deux colonnes et une ligne par paire libelle/effectif
1892 *   puis une ligne totalisant les effectifs s'il y a plus d'une ligne.
1893 *
1894 * @note
1895 *   Les classes CSS sont utilisees comme cle des tables parce-qu'il ne doit y en avoir qu'une par ligne.
1896 */
1897function association_totauxinfos_effectifs($legende='', $lignes, $decimales_significatives=0) {
1898        if (!is_array($lignes) OR !$lignes)
1899                return '';
1900        $nbr_actuel = $nbr_total = 0;
1901        $res = '<table width="100%" class="asso_infos">';
1902        $res .= "\n<caption>". _T('asso:totaux_nombres', array('de_par'=>_T("local:$legende"))) ."</caption>\n";
1903        foreach ($lignes as $classe_css=>$params) {
1904                $res .= "<tr class='$classe_css'>";
1905                $res .= '<td class="text">'. $params[2]. association_langue($params[0]) .$params[3]."</td>\n";
1906                $nbr_actuel = is_array($params[1]) ? call_user_func_array('sql_countsel', $params[1]) : $params[1] ;
1907                $res .= '<td class="' .($decimales_significatives?'decimal':'integer') .'">'. association_formater_nombre($nbr_actuel, $decimales_significatives) ."</td>\n";
1908                $nbr_total += $nbr_actuel;
1909                $res .= "</tr>\n";
1910        }
1911        if ( count($lignes)>1 ) {
1912                $res .= '<tr><th class="text">'._T('asso:liste_nombre_total')."</th>\n";
1913                $res .= '<th class="' .($decimales_significatives?'decimal':'integer') .'">'. association_formater_nombre($nbr_total, $decimales_significatives) .'</th></tr>';
1914        }
1915        return $res."</table>\n";
1916}
1917
1918/**
1919 * Tableau des totaux comptables
1920 *
1921 * @param string $legende
1922 *   Complement du titre du tableau
1923 * @param float $somme_recettes
1924 *   Total des recettes
1925 * @param float $somme_depenses
1926 *   Total des depenses
1927 * @return string $res
1928 *   Table HTML presentant les recettes (sur une ligne) et les depenses (sur une autre ligne), puis le solde (sur une derniere ligne)
1929 *
1930 * @attention
1931 *   Tous ces parametres sont facultatifs, mais un tableau est quand meme genere dans tous les cas !
1932 */
1933function association_totauxinfos_montants($legende='', $somme_recettes=0, $somme_depenses=0) {
1934        $res = '<table width="100%" class="asso_infos">';
1935        $res .= '<caption>'. _T('asso:totaux_montants', array('de_par'=>_T("local:$legende"))) ."</caption><tbody>\n";
1936        $recettes = is_array($somme_recettes) ? call_user_func_array('sql_getfetsel', $somme_recettes) : $somme_recettes ;
1937#       if ($recettes) {
1938                $res .= "<tr class='impair'>"
1939                . '<th class="entree">'. _T('asso:bilan_recettes') ."</th>\n"
1940                . '<td class="decimal">' .association_formater_prix($recettes). ' </td>'
1941                . "</tr>\n";
1942#       }
1943        $depenses = is_array($somme_depenses) ? call_user_func_array('sql_getfetsel', $somme_depenses) : $somme_depenses ;
1944#       if ($depenses) {
1945                $res .= '<tr class="pair">'
1946                . '<th class="sortie">'. _T('asso:bilan_depenses') ."</th>\n"
1947                . '<td class="decimal">'.association_formater_prix($depenses) ."</td>\n"
1948                . "</tr>\n";
1949#       }
1950        if ($recettes && $depenses) {
1951                $solde = $recettes-$depenses;
1952                $res .= '<tr class="'.($solde>0?'impair':'pair').'">'
1953                . '<th class="solde">'. _T('asso:bilan_solde') ."</th>\n"
1954                . '<td class="decimal">'.association_formater_prix($solde)."</td>\n"
1955                . "</tr>\n";
1956        }
1957        return $res.'</tbody></table>';
1958}
1959
1960/** @} */
1961
1962
1963/*****************************************
1964 * @defgroup association_bloc
1965 *
1966 *
1967** @{ */
1968
1969/**
1970 * Boite d'infos sur un objet (colonne gauche)
1971 *
1972 *
1973 * @note
1974 *   Une certaine similitude avec http://programmer.spip.org/boite_infos :)
1975  */
1976function association_bloc_infosgauche($TitreObjet, $NumObjet, $DesLignes=array(), $ObjetEtendu='') {
1977        $res = debut_boite_info(TRUE);
1978        $res .= association_totauxinfos_intro($TitreObjet, $TitreObjet, $NumObjet, $DesLignes, $ObjetEtendu);
1979        $res .= association_date_du_jour();
1980        $res .= fin_boite_info(TRUE);
1981        return $res;
1982}
1983
1984/**
1985 * Demande de confirmation dans la suppression d'un objet
1986 *
1987 * @param string $type
1988 *   Type d'objet a supprimer
1989 * @param int $id
1990 *   ID de l'objet a supprimer
1991 * @param string $retour
1992 *   Nom du fichier d'action vers lequel le formulaire sera redirige, sans le prefixe "supprimer_".
1993 *   Par defaut, quand rien n'est indique, c'est l'objet suffixe de "s" qui est utilise
1994 */
1995function association_bloc_suppression($type, $id, $retour='') {
1996        $res = _T('asso:objet_num', array('objet'=>$type,'num'=>$id));
1997        $res = _T('asso:vous_aller_effacer', array('quoi'=>'<i>'.$res.'</i>'));
1998        $res = '<p><strong>'. $res  .'</strong></p><p class="boutons"><input type="submit" value="'. _T('asso:bouton_confirmer') .'" /></p>';
1999        return redirige_action_post("supprimer_{$type}s", $id, ($retour?$retour:$type.'s'), '', $res);
2000}
2001
2002/**
2003 * Bloc (tableau en ligne) d'affinage (filtrage) des resultats dans les pages principales... (ici il s'agit de la navigation au sein des donnees tabulaires --un grand listing-- d'un module...)
2004 *
2005 * @param array $liste_filtres
2006 *   Filtres natifs du plugin (identifiant prefixe de "association_selectionner_") :
2007 *   'identifiant_du_filtre'=>array('liste','des','parametres')
2008 * @param string $exec
2009 *   Nom du fichier "exec" auquel le formulaire sera soumis
2010 * @param string|array $supplements
2011 *   Utilisation d'autres filtres ou code supplementaire a rajourer a la fin
2012 *   - Chaine HTML a rajouter
2013 *   - Tableau des 'identifiant_filtre'=>"code HTML du filtre" a rajouter
2014 * @param bool $td
2015 *   Indique s'il faut generer un tableau (vrai, par defaut) ou une liste (faux)
2016 * @return string $res
2017 *   Form-HTML des filtres
2018 * @note
2019 *   Ici il s'agit d'un vrai formulaire qui influe sur les donnees affichees
2020 *   et non sur la fonctionnalite en cours (onglet), contrairement aux apparences
2021 *   (le passage de parametre se faisant par l'URL, celle-ci change)
2022 *   http://comments.gmane.org/gmane.comp.web.spip.devel/61824
2023 */
2024function association_bloc_filtres($liste_filtres, $exec='', $supplements='', $td=TRUE) {
2025        $res = '<form method="get" action="'. ($exec?generer_url_ecrire($exec):'') .'">';
2026        if ($exec)
2027                $res .= "\n<div><input type='hidden' name='exec' value='$exec' /></div>";
2028        $res .= "\n<". ($td?'table width="100%"':'ul') .' class="asso_tablo_filtres">'. ($td?'<tr>':'');
2029        foreach($liste_filtres as $filtre_selection =>$params) {
2030                $res .= ($td?'<td':'<li') ." class='filtre_$filtre_selection'>". call_user_func_array("association_selectionner_$filtre_selection", association_recuperer_liste($params, FALSE) ) . ($td?"</td>\n":'</li>');
2031        }
2032        if ( is_array($supplements) ) {
2033                foreach ($supplements as $nom => $supplement) {
2034                        $res .= ($td?'<td':'<li') ." class='filtre_$nom'>$supplement</". ($td?'td>':'li>');
2035                }
2036        } else {
2037                $res .= $supplements;
2038        }
2039        $res .= ($td?'<td':'<li') . ' class="boutons"><input type="submit" value="'. _T('asso:bouton_lister') .'" />' . ($td?"</td>\n":'</li>');
2040        return $res. ($td?'</tr></table':'</ul>') .">\n</form>\n";
2041}
2042
2043/**
2044 * Boite affichant le formulaire pour genere le PDF de la/le liste/tableau
2045 *
2046 * @param string $objet
2047 *   Nom de l'objet : il s'agit imperativement d'un objet du plugin,
2048 *   correspondant a une table avec le nom de l'objet suffixe de "s" et prefixe
2049 *   de "spip_asso" (cela exclu quand meme les tables du plugin qui n'ont pas de
2050 *   "s" final !)
2051 * @param string $params
2052 * @param string $prefixeLibelle
2053 *   Prefixe rajoute au nom du champ pour former la chaine de langue (dont le
2054 *   nommage est systematise dans "Associaspip")
2055 * @param array $champsExclus
2056 *   Liste (seules les valeurs du tableau sont prises en compte) des champs a ne
2057 *   pas prendre en compte : tous les autres champs de la table sont recuperes
2058 *   (mais seuls les champs geres par "Associaspip" et "Interface Champs Extras 2"
2059 *   seront affiches/proposes dans le formulaire, d'ou pas d'exclu par defaut)
2060 * @param bool $coords
2061 *   Indique s'il faut (vrai) prendre en compte ou pas (faux) le plugin "Coordonnees"
2062 * @return string $res
2063 *   Form HTML complet dans un cadre. Ce formulaire sera traite par l'exec de
2064 *   l'objet prefixe de "pdf_"
2065 */
2066function association_bloc_listepdf($objet, $params=array(), $prefixeLibelle='', $champsExclus=array(), $coords=true) {
2067        $champsExtras = association_trouver_iextras("asso_$objet");
2068        $desc_table = charger_fonction('trouver_table', 'base'); // http://doc.spip.org/@description_table deprecier donc preferer http://programmer.spip.net/trouver_table,620
2069        $champsPresents = $desc_table("spip_asso_${objet}s");
2070        $frm = '<ul><li class="edit_champs">';
2071        foreach ($champsPresents['field'] as $k => $v) { // donner le menu des choix
2072                if ( !in_array($k, $champsExclus) ) { // affichable/selectionnable (champ ayant un libelle declare et connu)
2073                                $lang_clef = $prefixeLibelle.$k;
2074                                $lang_texte = association_langue($lang_clef);
2075                                if ( $lang_clef!=str_replace(' ', '_', $lang_texte) ) { // champ natif du plugin
2076                                        $frm .= "<div class='choix'><input type='checkbox' name='champs[$k]' id='liste_${objet}s_$k' /><label for='liste_${objet}s_$k'>$lang_texte</label></div>";
2077                                } elseif( array_key_exists($k,$champsExtras) ) { // champs rajoute via cextra
2078                                        $frm .= "<div class='choix'><input type='checkbox' name='champs[$k]' id='liste_${objet}s_$k' /><label for='liste_${objet}s_$k'>$champsExtras[$k]</label></div>";
2079                                }
2080                        }
2081        }
2082        if ($coords) {
2083                        $frm .= '<div class="choix"><input type="checkbox" name="champs[email]" id="liste_'.$objet.'s_email" /><label for="liste_'.$objet.'s_email">'. _T('asso:adherent_libelle_email') .'</label></div>'; // on ajoute aussi l'adresse electronique principale (table spip_auteurs ou spip_emails)
2084                        if (test_plugin_actif('COORDONNEES')) {
2085                                $frm .= '<div class="choix"><input type="checkbox" name="champs[adresse]" id="liste_'.$objet.'_s_adresse" /><label for="liste_'.$objet.'_s_adresse">'. _T('coordonnees:adresses') .'</label></div>'; // on ajoute aussi l'adresse postale (table spip_adresses)
2086                                $frm .= '<div class="choix"><input type="checkbox" name="champs[telephone]" id="liste_'.$objet.'_s_telephone" /><label for="liste_'.$objet.'_s_telephone">'. _T('coordonnees:numeros') .'</label></div>'; // on ajoute aussi le numero de telephone (table spip_numeros)
2087                        }
2088        }
2089        foreach ($params as $k => $v) { // on fait suivre les autres parametres dont la liste des auteurs a afficher
2090                $frm .= '<input type="hidden" name="'.$k.'" value="'. htmlspecialchars($v, ENT_QUOTES, $GLOBALS['meta']['charset']) .'" />'; // http://stackoverflow.com/questions/46483/htmlentities-vs-htmlspecialchars
2091        }
2092        $frm .= '</li></ul>';
2093        $frm .= '<p class="boutons"><input type="submit" value="'. _T('asso:bouton_imprimer') .'" /></p>';
2094
2095        return $frm;
2096}
2097
2098/**
2099 * Listing sous forme de tableau HTML
2100 *
2101 * @param string $table
2102 *   nom de table SQL
2103 * @param ressource $reponse_sql
2104 *   Ressource de requete sql_select sur cette table (avec jointure eventuelle)
2105 *   http://doc.spip.org/@sql_select
2106 *   http://programmer.spip.net/sql_select,569
2107 * @param array $presentation
2108 *   Tableau decrivant les donnees affichees :
2109 *   'nom_ou_alias_du_champ' => array('chaine_de:langue_du_libelle_d_entete', 'nom_du_format', 'parametre1', ...)
2110 *   Le nom du format est celui de la fonction de formatage du meme nom prefixee de association_formater_
2111 * @param array $boutons
2112 *   array('bouton', 'parametre1', ...)
2113 *   Le nom du type de bouton est celui de la fonction d'action du meme nom prefixee de association_bouton_
2114 * @param string $cle1
2115 *   Nom (ou alias) de la colonne cle primaire,
2116 * @param array $extra
2117 *   Liste de classes supplemetaires appliquees alternativement aux lignes ;
2118 *   Ou tableau des valeur=>classe supplementaires appliquees aux lignes presentant la valeur
2119 * @param string $cle2
2120 *   Nom (ou alias) de la colonne dont les valeurs servent de cle de classe
2121 * @param int $selection
2122 *   ID de la cle primaire selectionnee
2123 * @return string $res
2124 *   Table-HTML listant les donnees formatees
2125 */
2126
2127function association_bloc_listehtml2($table, $reponse_sql, $presentation, $boutons=array(), $cle1='', $extra=array(), $cle2='', $selection=0) {
2128
2129        if ( $cle1 ) {
2130                if ( strpos($cle1, 'id_')===0 )
2131                        $objet = substr($cle1, 3);
2132                else
2133                        $objet = $cle1;
2134        }
2135        $res = '';
2136        foreach ($presentation as &$param) { // affecter le tableau au passage
2137                $entete = array_shift($param);
2138                $res .= '<th>'. ($entete ? association_langue($entete) : '&nbsp;' ) ."</th>\n";
2139        }
2140        $lignes = association_bloc_tr($reponse_sql, $extra, $cle1, $cle2, $objet, $presentation, $boutons, $selection);
2141        sql_free($reponse_sql);
2142
2143        if (!$lignes) return _T('asso:aucun');
2144
2145        if ( count($boutons) ) { // colonne(s) de bouton(s) d'action
2146                $res .= '<th colspan="'. count($boutons) .'" class="actions">'. _T('asso:entete_action' .(count($boutons)-1?'s':'')) ."</th>\n";
2147        }
2148
2149        $res =  '<table width="100%" class="asso_tablo"'. ($table ? " id='liste_$table'" : '') . ">\n<tr>$res</tr>\n$lignes</table>\n";
2150
2151
2152        if ( $cle1 && $selection ) {
2153// comme on ne peut placer un evenement "onLoad" que sur une ressource externe
2154// (IMG, FRAME, SCRIPT, BODY) ; il vaut mieux appliquer un SCRIPT inclus
2155// (tout juste apres ou dans HEAD si possible)
2156                $res .= '<script type="text/javascript"> document.getElementById("'.$objet.$selection.'").scrollIntoView(true); </script>' ; 
2157        }
2158        return $res;
2159}
2160
2161function association_bloc_tr($query, $extra, $cle1, $cle2, $objet, $presentation, $boutons, $selection) {
2162        $nbr_lignes = 0;
2163        $nbr_couleurs = count($extra);
2164        $class_sup = (is_array($extra) AND $nbr_couleurs);
2165        $res ='';
2166        while ($data = sql_fetch($query)) {
2167                if ($class_sup) { // on a  un tableau de classes supplementaires
2168                        if ( $cle2 ) { // lignes colorees selon les valeurs d'un champ
2169                                $tr_css = $extra[$data[$cle2]];
2170                        } else { // simple alternance de couleurs
2171                                $nbr_lignes++;
2172                                $tr_css = $extra[$nbr_lignes%$nbr_couleurs];
2173                        }
2174                } elseif ( $extra ) { // classe supplementaire appliquee inconditionnellement
2175                                $tr_css = $extra;
2176                } else $tr_css = '';
2177                if ( $cle1 && $data[$cle1]==$selection ) {
2178                        $tr_css = 'surligne';
2179                }
2180                $res .= '<tr'. ($cle1?' id="'.$objet.$data[$cle1].'"':'') . ($tr_css?' class="'.$tr_css.'"':'') .'>' .
2181                association_bloc_format($presentation, $data, $cle1, $selection).
2182                association_bloc_bouton($boutons, $data[$cle1]) .
2183                "</tr>\n";
2184        }
2185        return $res;
2186}
2187
2188function association_bloc_format($presentation, $data, $cle1, $selection) {
2189        $res = '';
2190        foreach ($presentation as $champ=>$params) {
2191                $format = array_shift($params);
2192                switch ($format) {
2193                                case 'date' :
2194                                case 'heure' :
2195                                        $td_css = 'date';
2196                                        break;
2197                                case 'duree' :
2198                                case 'nombre' :
2199                                case 'prix' :
2200                                        $td_css = 'decimal';
2201                                        break;
2202                                case 'entier' :
2203                                        $td_css = 'integer';
2204                                        $format = 'nombre'; $params = array(0);
2205                                        break;
2206                                case 'puce' :
2207                                case 'logo' :
2208                                        $td_css = 'image';
2209                                        break;
2210                                case 'code' :
2211                                case 'texte' :
2212                                default :
2213                                        $td_css = 'text';
2214                                        break;
2215                }
2216                if ( $data[$cle1]==$selection )
2217                        $td_css .= ' surligne';
2218                array_unshift($params, $data[$champ]);
2219                $format = call_user_func_array("association_formater_$format", $params);
2220                $res .= '<td class="'.$td_css.'">'. $format ."</td>\n";
2221        }
2222        return $res;
2223}
2224
2225function association_bloc_bouton($boutons, $champ) {
2226        $res = '';
2227        foreach ($boutons as $params) {
2228                $type = array_shift($params);
2229                foreach ($params as &$param) {
2230                        $param = str_replace('$$', $champ, $param);
2231                }
2232                $res .= call_user_func_array("association_bouton_$type", $params);
2233        }
2234        return $res;
2235}
2236/** @} */
2237
2238
2239/*****************************************
2240 * @defgroup sql_asso1
2241 * Extension de l'API SQL pour Associaspip (operations qui reviennent souvent)
2242 *
2243 * @param string $table
2244 *   Le nom de l'objet : correspond a la table sans prefixe "spip_asso" et sans le "s" final
2245 * @param int $id
2246 *   ID de la ligne a recuperer
2247 *
2248** @{ */
2249
2250/**
2251 * Recupere dans une chaine un champ d'une table spip_asso_XXs pour un enregistrement identifie par son id_XX
2252 *
2253 * @param string $champ
2254 *   Nom du champ recherche
2255 * @return string
2256 *   Valeur du champ recherche
2257 *
2258 * @note Conversion d'anciennes fonctions :
2259 * - exercice_intitule($exo) <=> sql_asso1champ('exercice', $exo, 'intitule')
2260 * - exercice_date_debut($exercice) <=> sql_asso1champ('exercice', $exercice, 'debut')
2261 * - exercice_date_fin($exercice) <=> sql_asso1champ('exercice', $exercice, 'fin')
2262 */
2263function sql_asso1champ($table, $id, $champ) {
2264        return sql_getfetsel($champ, table_objet_sql("asso_$table"), id_table_objet("asso_$table").'='.intval($id) );
2265}
2266
2267/**
2268 * Recupere dans un tableau associatif un enregistrement d'une table spip_asso_XX identifie par son id_XX
2269 *
2270 * @return array
2271 *   Tableau des champs sous forme : 'nom_du_champ'=>"contenu du champ"
2272 */
2273function sql_asso1ligne($table, $id) {
2274        return sql_fetsel('*', table_objet_sql("asso_$table"), id_table_objet("asso_$table").'='.intval($id) );
2275}
2276
2277/**
2278 * Genere la borne (partie SQL LIMIT) d'enregistrements retournes
2279 *
2280 * @param string $valeur
2281 *   Nom du champ utilise pour passer la page courante
2282 * @return string
2283 *   Chaine de la partie LIMIT-SQL pour sql_select et similaires
2284 */
2285function sql_asso1page($valeur='debut', $req=TRUE) {
2286        $valeur = intval($req?_request($valeur):$valeur);
2287        return "$valeur,"._ASSOCIASPIP_LIMITE_SOUSPAGE;
2288}
2289
2290/**
2291 * Operation ensembliste sur deux requetes
2292 *
2293 * @param string $operateur
2294 *   Operation ensembliste a realiser : UNION (reunion, par defaut), INTERSECT
2295 *   (intersection), MINUS (difference) ou EXCEPT ; sans duplication ou avec (ALL)
2296 * @param array $q...
2297 *   Elements d'une requete telle que passee a "sql_select"
2298 * @return ressource
2299 *
2300 * @note
2301 *   D'une part le support des differents operateurs varie d'un SGBDR a l'autre.
2302 *   D'autre part il est souvent possible d'obtenir le meme resultat sans leur
2303 *   usage mais au prix de requetes bien moins simples.
2304 *   http://www.gplivna.eu/papers/sql_set_operators.htm
2305 *   http://www.dba-ora.fr/article-sql-union-intersect-minus-101360158.html
2306 *   http://cerig.efpg.inpg.fr/tutoriel/bases-de-donnees/chap21.htm
2307 *   Le besoin de cette fontion vient de la necessite de reunir plusieurs etats
2308 *   en une requte pour "association_bloc_listehtml()" et de ne rien trouver dans
2309 *   l'API SQL de SPIP. Entre temps, la solution a ete de recourir a des CASE WHEN...THEN... END
2310 *   qui semble aussi (ou plus) performant qu'une reUNION d'une meme table sur
2311 *   elle-meme et tout aussi portable... La discussion reste ouverte...
2312 *   http://www.sqlservercentral.com/Forums/Topic686395-8-1.aspx
2313 *   http://www.sswug.org/articles/viewarticle.aspx?id=19349
2314 *   http://db2portal.blogspot.fr/2009/11/replacing-union-with-case.html
2315 *   http://www.componentace.com/help/absdb_manual/increasesqlperformance.htm
2316 *   http://dba.stackexchange.com/questions/21904/refactoring-series-of-unions-in-single-table-sql-sybase
2317 *   http://stackoverflow.com/questions/2563811/sqlite-is-the-case-statement-expensive
2318 *   http://www.pcreview.co.uk/forums/case-access-sql-t1169064.html
2319 */
2320function sql_asso1set($operateur='UNION', $q1=array(), $q2=array() ) {
2321        $nbr_requetes = func_num_args()-1;
2322        if ( $nbr_requetes<2 ) // il en faut au moins 2 !
2323                return FALSE;
2324        if ( !$operateur ) // non precise ?
2325                $operateur = 'UNION';
2326        $requete_finale = func_get_arg(1);
2327        for ( $i=2; $i<$nbr_requetes; $i++ ) {
2328                $requete_finale .= "\n $operateur \n". call_user_func_array('sql_get_select', func_get_arg($i) );
2329        }
2330        return sql_querry($requete_finale);
2331}
2332
2333/** @} */
2334
2335
2336/*****************************************
2337 * @defgroup association_passeparam
2338 * Les champs passes aux "exec" par l'URL etant normalises pour les filtres,
2339 * ils partagent le meme code de passage de valeur et les memes noms de parametres
2340 * (ce qui n'est pas le cas avec association_recuperer_ !)
2341 *
2342 * @param string $type
2343 *   Type d'objet|page pour lequel on passe le parametre en question.
2344 * @param string $objet
2345 *   Nom de la table (sans prefixe "spip") contenant la collection d'objets.
2346 *   Sa presence indique de retourner des parametres supplementaires et/ou de
2347 *   faire des controles supplementaires. Ce parametre est surtout utlise dans les pages d'edition/suppression
2348 * @return string|array $res
2349 *   Valeur du request...
2350 *   Ou une liste comportant la valeur du parametre au debut et d'autres valeurs
2351 *   utiles induites.
2352 *
2353** @{ */
2354
2355
2356/**
2357 * &id=
2358 *
2359 * @return int $id
2360 *
2361 */
2362function association_passeparam_id($type='') {
2363        if ($type) // recuperer en priorite : id_compte, id_don, id_evenement, id_ressource, id_vente, etc.
2364                $id = intval(_request("id_$type", $_GET));
2365        else
2366                $id = 0;
2367        // si pas d'id_... alors c'est le nom generique qui est utilise
2368        return $id ? $id : intval(_request('id'));
2369}
2370
2371/**
2372 * Retourne la ligne SQL correspondant a la table donnee et au ID dans l'URL
2373 * et controle l'autorisation
2374 *
2375 * @param string $type
2376 *   Nom de l'ID
2377 * @param string $table
2378 *   Nom de la table
2379 * @param string $controle
2380 *   Nom du verbe d'autorisation
2381 * @param string $controle
2382 *   Nom de l'objet d'autorisation
2383 * @return array(int, array) | array()
2384 *   Numero de l'ID et ligne correspondante dans la table si ok, vide sinon
2385 *
2386 */
2387function association_controle_id($type, $table, $controle='') {
2388        if ($id = association_passeparam_id($type)) {
2389                include_spip('base/association');
2390                $trouver_table = charger_fonction('trouver_table', 'base');
2391                $table = "spip_$table";
2392                $desc = $trouver_table($table, $serveur);
2393                $id_table = $desc['key']["PRIMARY KEY"];
2394                $type = sql_fetsel('*', $table, "$id_table=$id");
2395        }
2396        // Si ok, $type est devenu $type la ligne.
2397        if ($id AND $type AND (!$controle OR autoriser($controle, 'association', $id)))
2398                return array($id, $type);
2399        include_spip('inc/minipres');
2400        // $type est un tableau ssi autorisation fautive
2401        echo minipres(is_array($type) ? '' :  _T('zxml_inconnu_id', array('id'=>$id)));
2402        return array();
2403}
2404
2405/**
2406 * &annee=
2407 *
2408 * @return int $an
2409 * @return array($an, $sql_where)
2410 */
2411function association_passeparam_annee($type='', $objet='', $id=0) {
2412        if ($type) // recuperer en priorite :
2413                $an = intval(_request("annee_$type", $_GET));
2414        else
2415                $an = 0;
2416        if (!$an) // pas d'annee_... alors c'est le nom generique qui est utilise
2417                $an = intval(_request('annee'));
2418        if (!$an) // annee non precisee
2419                $an = date('Y'); // on prend l'annee courante
2420        if ($type && $objet) {
2421//              $desc_table = charger_fonction('trouver_table', 'base');
2422                if ($id) { // on veut un enregistrement precis : on ne va pas tenir compte de la l'annee passee en requete...
2423                        $an = sql_getfetsel("DATE_FORMAT(date_$type, '%Y')", table_objet_sql($objet), id_table_objet($objet).'='.sql_quote($id) ); // ...on recupere l'annee correspondante a l'enregistrement recherche
2424                } else { // on peut faire mieux que prendre l'annee courante ou une annee farfelue passee en parametre
2425                        $an = min(sql_getfetsel("MAX(DATE_FORMAT(date_$type, '%Y')) AS an_max", table_objet_sql($objet), ''), $an);
2426                        $an = max(sql_getfetsel("MIN(DATE_FORMAT(date_$type, '%Y')) AS an_min", table_objet_sql($objet), ''), $an);
2427                }
2428                if (!$an) // ID inexistant (donc annee non trouvee) ou table vide (du coup annee vide)
2429                        $an = date('Y'); // on prend l'annee courante retomber sur nos pattes et surtout ne pas fausser la requete
2430                return array($an, "DATE_FORMAT(date_$type, '%Y')=$an");
2431        } else
2432                return $an;
2433}
2434
2435/**
2436 * &exercice=
2437 *
2438 * @return int $exo
2439 * @return array($exo, $sql_where)
2440 */
2441function association_passeparam_exercice($type='', $objet='', $id=0) {
2442        $exo = intval(_request('exercice'));
2443        if (!$exo) // exercice non precise
2444                $exo = intval(sql_getfetsel('id_exercice','spip_asso_exercices','','','date_debut DESC')); // on recupere le dernier exercice en date
2445        if ($type && $objet) {
2446                if ($id) { // on veut un enregistrement precis : on ne va pas tenir compte de l'exercice passe en requete...
2447                        $dt = sql_getfetsel("date_$type", table_objet_sql($objet), id_table_objet($objet).'='.sql_quote($id) ); // ...on recupere la date correspondante a l'enregistrement recherche
2448                        $exercice = sql_fetsel('*','spip_asso_exercices', "date_debut<='$dt' AND date_fin>='$dt'", '','date_debut DESC'); // on recupere le dernier exercice correspondant
2449                }
2450                if (!$exercice) { // pas d'ID ou table vide ou mauvais ID
2451                        $exercice = sql_fetsel('*','spip_asso_exercices', "id_exercice=$exo"); // on recupere l'exercice indique
2452                }
2453                return array($exercice['id_exercice'], "date_$type>='$exercicee[date_debut]' AND date_$type<='$exercice[date_fin]'");
2454        } else
2455                return $exo;
2456}
2457
2458/**
2459 * &statut=
2460 *
2461 * @return string $statut
2462 * @return array($statut, $sql_where)
2463 * Pour l'instant, appele uniquement dans exec/adherents.php vers la ligne 25
2464 */
2465function association_passeparam_statut($type='', $defaut='') {
2466        if ($type) // recuperer en priorite :
2467                $statut = trim(_request("statut_$type", $_GET));
2468        else
2469                $statut = '';
2470        if (!$statut) // pas de statut_... alors c'est le nom generique qui est utilise
2471                $statut = trim(_request('statut'));
2472        if (!$statut) // statut non precise non precisee
2473                $statut = $defaut; // on prend celui par defaut (tous)
2474        if ($defaut && $type) {
2475                switch ($type) {
2476                        case 'interne' :
2477                                if (in_array($statut, $GLOBALS['association_liste_des_statuts'] ))
2478                                        $sql_where = 'statut_interne='. sql_quote($statut);
2479                                elseif ($statut=='tous')
2480                                        $sql_where = "statut_interne LIKE '%'";
2481                                else {
2482                                        set_request('statut_interne', $defaut);
2483                                        $statuts = $GLOBALS['association_liste_des_statuts'];
2484                                        $exclure = array_shift($statuts);
2485                                        $sql_where = sql_in('statut_interne', $statuts);
2486                                }
2487                                break;
2488                }
2489                return array($statut, $sql_where);
2490        } else
2491                return $statut;
2492}
2493
2494/**
2495 * &exercice= | &annee=
2496 *
2497 * @see association_passeparam_annee
2498 * @see association_passeparam_exercice
2499 */
2500function association_passeparam_periode($type='', $objet='', $id=0) {
2501        $PeriodeCompatable = 'association_passeparam_'.($GLOBALS['association_metas']['exercices']?'exercice':'annee');
2502        return $PeriodeCompatable($type, $objet, $id);
2503}
2504
2505/** @} */
2506
2507
2508/*****************************************
2509 * @defgroup association_chargeparam
2510 * Charger des parametres comptables dans le contexte d'un formulaire
2511 *
2512 * @param string $type
2513 * @param int $id
2514 * @param array &$contexte
2515 * @return array $contexte
2516 *   Valeur(s) a charger.
2517 *
2518** @{ */
2519
2520function association_chargeparam_operation($type, $id, &$contexte) {
2521        if ( $id ) { // si c'est une modification, on charge ses id_compte et journal depuis la table asso_comptes
2522                list($id_compte, $journal) = sql_fetsel('id_compte, journal', 'spip_asso_comptes', 'imputation='. sql_quote($GLOBALS['association_metas']["pc_$type"]) .' AND id_journal='. sql_quote($id) ); // on recupere id_compte et journal dans la table des asso_compteS
2523        } else {  // si c'est une nouvelle operation, on charge id_compte et journal vides
2524                $id_compte = $journal = '';
2525        }
2526        $contexte['journal'] = $journal; // ajoute le  journal qui ne se trouve pas dans la table chargee par editer_objet_charger mais dans asso_comptes plutot
2527        $contexte['_hidden'] .= "<input type='hidden' name='id_compte' value='$id_compte' />"; // on concatene aux _hidden de $contexte , id_compte qui sera utilise dans l'action
2528        $contexte['id_compte'] = $id_compte; // sera utilise par association_chargeparam_destinations()
2529        return $contexte;
2530}
2531
2532function association_chargeparam_destinations($type, &$contexte) {
2533        if ($GLOBALS['association_metas']['destinations'] AND $contexte['id_compte']) {
2534                // Recuperer les destinations associees a id_compte
2535                // pour ajouter au contexte : id_dest, montant_dest, defaut_dest
2536                // ces variables sont recuperees par la balise dynamique
2537                include_spip('inc/association_comptabilite');
2538                $dest = association_liste_destinations_associees($contexte['id_compte']);
2539                if ($dest) {
2540                        $contexte['id_dest'] = array_keys($dest);
2541                        $contexte['montant_dest'] = array_values($dest);
2542                } else {
2543                        $contexte['id_dest'] = '';
2544                        $contexte['montant_dest'] = '';
2545                }
2546                $contexte['defaut_dest'] = ($type ? $GLOBALS['association_metas']["dc_$type"] : '');
2547        }
2548        return $contexte;
2549}
2550
2551/** @} */
2552
2553
2554/*****************************************
2555 * @defgroup divers
2556 * Inclassables
2557 *
2558** @{ */
2559
2560/**
2561 * Affichage du message indiquant la date
2562 * (et l'heure si option activee)
2563 *
2564 * @param bool $phraser
2565 *   Indique si l'horodatage est insere dans la chaine de langue prevue a cet
2566 *   effet (vrai, par defaut) ou s'il est renvoye seul (faux)
2567 * @return string $res
2568 */
2569function association_date_du_jour($phraser=TRUE) {
2570        $frmt_m = date('Y-m-d'. (_ASSOCIASPIP_AUJOURDHUI_HORAIRE?'\TH:i:s':'') ); // format machine-parsable : idealement "\TH:i:s.uP" mais il faut PHP "up"date (plus precisement 5.1.0 pour "e" et 5.1.3 pour "P" et 5.2.0 pour "u")
2571        $format = 'affdate_'. (_ASSOCIASPIP_AUJOURDHUI_HORAIRE?'heure':'base');
2572        $frmt_h = $format($frmt_m, 'entier');  // format human-readable
2573        if ( $phraser )
2574                return '<p class="clear date">'. _T('asso:date_du_jour', array('date'=> (@$GLOBALS['meta']['html5']?'<time datetime="':'<abbr title="'). $frmt_m.'">'.$frmt_h. (@$GLOBALS['meta']['html5']?'</time>':'</abbr>') ) ) .'</p>';
2575        else
2576                return $frmt_h;
2577}
2578
2579/**
2580 * Injection de "association.css" dans le "header" de l'espace prive
2581 * @param string $flux
2582 * @return string $c
2583 */
2584function association_header_prive($flux) {
2585        $c = direction_css(find_in_path('association.css'));
2586        return "$flux\n<link rel='stylesheet' type='text/css' href='$c' />";
2587}
2588
2589/**
2590 * Filtre pour "afficher" ou "cacher" un bloc div
2591 *
2592 * Utilise dans le formulaire cvt "editer_asso_comptes.html"
2593 *
2594 * @param string $type_operation
2595 * @param string $list_operation
2596 * @return string $res
2597 */
2598function affichage_div($type_operation, $list_operation) {
2599        if(strpos($list_operation, '-')) {
2600                $operations = explode('-', $list_operation);
2601                $res = 'cachediv';
2602                for($i=0;$i<count($operations);$i++) {
2603                        $operation = $GLOBALS['association_metas']['classe_'.$operations[$i]];
2604                        if($type_operation===$operation) {
2605                                $res = '';
2606                                break;
2607                        }
2608                }
2609        } else {
2610                $res = ($type_operation===$GLOBALS['association_metas']['classe_'.$list_operation])?'':'cachediv';
2611        }
2612        return $res;
2613}
2614
2615/**
2616 * Recupere la liste des champs extras manuellement rajoutes a un objet
2617 *
2618 * @param string $ObjetEtendu
2619 *   Nom de l'objet dont on veut recuperer les champs etendus
2620 * @param int $id
2621 *   ID de l'objet dont il veut recuperer aussi les donnees
2622 *   Par defaut : aucun (i.e. 0)
2623 * @return array $champsExtrasVoulus
2624 *   - si on ne veut pas de donnee :
2625 *     'nom_de_la_colonne'=>"Libelle du champ"
2626 *   - si on veut aussi les donnees :
2627 *     'nom_de_la_colonne'=>array( "Libelle du champ", "Donnee formatee", "Donnee brute SQL")
2628 */
2629function association_trouver_iextras($ObjetEtendu, $id=0) {
2630        $champsExtrasVoulus = array();
2631        if (test_plugin_actif('IEXTRAS')) { // le plugin "Interfaces pour ChampsExtras2" est installe et active : on peut donc utiliser les methodes/fonctions natives...
2632                include_spip('inc/iextras'); // charger les fonctions de l'interface/gestionnaire (ce fichier charge les methode du core/API)
2633                include_spip('inc/cextras_gerer'); // semble necessaire aussi
2634                if ($id)
2635                        include_spip('cextras_pipelines'); // pour eviter le "Fatal error : Call to undefined function cextras_enum()" en recuperant un fond utilisant les enum...
2636                $ChampsExtrasGeres = iextras_get_extras_par_table(); // C'est un tableau des differents "objets etendus" (i.e. tables principaux SPIP sans prefixe et au singulier -- par exemple la table 'spip_asso_membres' correspond a l'objet 'asso_membre') comme cle.
2637                foreach ($ChampsExtrasGeres[$ObjetEtendu] as $ChampExtraRang => $ChampExtraInfos ) { // Pour chaque objet, le tableau a une entree texte de cle "id_objet" et autant d'entrees tableau de cles numerotees automatiquement (a partir de 0) qu'il y a de champs extras definis.
2638                        if ( is_array($ChampExtraInfos) ) { // Chaque champ extra defini est un tableau avec les cle=>type suivants : "table"=>string, "champ"=>string, "label"=>string, "precisions"=>string, "obligatoire"=>string, "verifier"=>bool, "verifier_options"=>array, "rechercher"=>string, "enum"=>string, "type"=>string, "sql"=>string, "traitements"=>string, "saisie_externe"=>bool, "saisie_parametres"]=>array("explication"=>string, "attention"=>string, "class"=> string, "li_class"]=>string,)
2639                                $label = _TT($ChampExtraInfos['label']); // _TT est defini dans cextras_balises.php
2640                                if ( $id ) {
2641                                        $desc_table = charger_fonction('trouver_table', 'base');
2642                                        $champs = $desc_table("spip_$ChampExtraInfos[table]s");
2643                                        $datum_raw = sql_getfetsel($ChampExtraInfos['champ'], table_objet_sql($ChampExtraInfos['table']), $champs['key']['PRIMARY KEY'].'='.sql_quote($id) ); // on recupere les donnees...
2644                                        $datum_parsed = recuperer_fond('extra-vues/'.$ChampExtraInfos['type'], array (
2645                                                'champ_extra' => $ChampExtraInfos['champ'],
2646                                                'label_extra' => '', // normalement : _TT($ChampExtraInfos['label']), avec la chaine vide on aura juste "<strong></strong> " a virer...
2647                                                'valeur_extra' => $ChampExtraInfos['traitement']?$ChampExtraInfos['traitement']($datum_raw):$datum_raw,
2648                                                'enum_extra' => $ChampExtraInfos['enum'], // parametre indispensable pour les champs de type "option"/"radio"/"case" http://forum.spip.net/fr_245942.html#forum245980
2649                                        )); // resultat du pipeline "affiche_contenu_objet" altere (prive du libelle du champ qui est envoye separement)
2650                                        $champsExtrasVoulus[$ChampExtraInfos['champ']] = array( $label, str_ireplace('<strong></strong>', '', $datum_parsed), $datum_raw );
2651                                } else {
2652                                        $champsExtrasVoulus[$ChampExtraInfos['champ']] = $label;
2653                                }
2654                        }
2655                }
2656        } else { // le plugin "Interfaces pour ChampsExtras2" n'est pas actif :-S Mais peut-etre a-t-il ete installe ?
2657                $ChampsExtrasGeres = @unserialize(str_replace('O:10:"ChampExtra"', 'a', $GLOBALS['meta']['iextras'])); // "iextras (interface)" stocke la liste des champs geres dans un meta. Ce meta est un tableau d'objets "ChampExtra" (un par champ extra) manipules par "cextras (core)". On converti chaque objet en tableau
2658                if ( !is_array($ChampsExtrasGeres) )
2659                        return array(); // fin : ChampsExtras2 non installe ou pas d'objet etendu.
2660                $TT = function_exists('_T_ou_typo') ? '_T_ou_typo' : '_T' ; // Noter que les <multi>...</multi> et <:xx:> sont aussi traites par propre() et typo() :  http://contrib.spip.net/PointsEntreeIncTexte
2661                foreach ($ChampsExtrasGeres as $ChampExtra) { // Chaque champ extra defini est un tableau avec les cle=>type suivants (les cles commencant par "_" initialisent des methodes de meme nom sans le prefixe) : "table"=>string, "champ"=>string, "label"=>string, "precisions"=>string, "obligatoire"=>string, "verifier"=>bool, "verifier_options"=>array, "rechercher"=>string, "enum"=>string, "type"=>string, "sql"=>string, "traitements"=>string, "_id"=>string, "_type"=>string, "_objet"=>string, "_table_sql"=>string, "saisie_externe"=>bool, "saisie_parametres"]=>array("explication"=>string, "attention"=>string, "class"=> string, "li_class"]=>string,)
2662                        if ($ChampExtra['table']==$ObjetEtendu) // c'est un champ extra de la 'table' ou du '_type' d'objet qui nous interesse
2663                                $label = $TT($ChampExtra['label']);
2664                                if ( $id ) {
2665                                        $datum_raw = sql_getfetsel($ChampExtra['champ'], $ChampExtra['_table_sql'], id_table_objet($ChampExtra['_type']).'='.intval($id) ); // on recupere les donnees...
2666                                        switch ( $ChampExtra['type'] ) { // Comme on n'est pas certain de pouvoir trouver "inc/iextra.php" et "inc/cextra.php" on a des chance que foire par moment. On va donc gerer les cas courants manuellement.
2667                                                case 'case' : // "<select type='checkbox' .../>..."
2668                                                case 'option' : // "<select ...>...</select>"
2669                                                case 'radio' : // "<select type='radio' .../>..."
2670                                                        $valeurs = array();
2671                                                        $enum = explode("\r\n", $ChampExtra['enum']);
2672                                                        foreach ($enum as $pair) {
2673                                                                list($key, $value) = explode(',', $pair, 1);
2674                                                                $valeurs[$key] = $value;
2675                                                        }
2676                                                        $datum_parsed = $ChampExtra['traitement']?$ChampExtra['traitement']($valeurs[$datum_raw]):$valeurs[$datum_raw];
2677                                                        break;
2678                                                case 'oui_non' :
2679                                                        $datum_parsed = _T("item:$datum_raw");
2680                                                        break;
2681                                                case 'asso_categorie' :
2682                                                case 'asso_compte' :
2683                                                case 'asso_exercice' :
2684                                                case 'asso_membre' :
2685                                                case 'asso_ressource' :
2686                                                        $raccourci = substr($ChampExtra['type'], 4); // on vire le prefixe "asso_"
2687                                                        if ( $ChampExtra['traitement'] )
2688                                                                $datum_parsed = $ChampExtra['traitement']('[->'.$raccourci.$datum_raw.']');
2689                                                        else { // il faut une requete de plus
2690                                                                switch ($raccourci) { // $valeur prend ici le champ SQL contenant la valeur desiree.
2691                                                                        case 'categorie' :
2692                                                                                $valeur = 'libelle';
2693                                                                                break;
2694                                                                        case 'compte' :
2695                                                                                $valeur = 'justification';
2696                                                                                break;
2697                                                                        case 'exercice' :
2698                                                                                $valeur = 'intitule';
2699                                                                                break;
2700                                                                        case 'membre' :
2701                                                                                $valeur = 'nom_famille'; // il faudrait "concatener" : nom_famille, prenom, sexe ; le tout en fonction des metas... mais http://sql.1keydata.com/fr/sql-concatener.php
2702                                                                                break;
2703                                                                        case 'ressource' :
2704                                                                                $valeur = 'intitule';
2705                                                                                break;
2706                                                                        default :
2707                                                                                $valeur = 'titre'; // sauf coincidence heurese, on devrait avoir une erreur...
2708                                                                                break;
2709                                                                }
2710                                                                $datum_parsed = association_formater_idnom($datum_raw, array(table_objet_sql($ChampExtra[type]), $valeur, 'id_'.$raccourci) , ''); // on recupere la donnee grace a la cle etrangere... (il faut que la table soit suffixee de "s" et que l'identifiant soit l'objet prefixe de "id_" :-S)
2711                                                        }
2712                                                        break;
2713                                                case 'asso_activite' :
2714                                                case 'asso_don' :
2715                                                case 'asso_vente' :
2716                                                        $raccourci = substr($ChampExtra['type'], 4); // on vire le prefixe "asso_"
2717                                                        if ( $ChampExtra['traitement'] )
2718                                                                $datum_parsed = $ChampExtra['traitement']('[->'.$raccourci.$datum_raw.']');
2719                                                        else
2720                                                                $datum_parsed = _T('asso:objet_num', array('objet'=>$raccourci, 'num'=>$datum_raw) );
2721                                                        break;
2722                                                case 'article' :
2723                                                case 'auteur' :
2724                                                case 'breve' :
2725                                                case 'document' :
2726                                                case 'evenement' :
2727                                                case 'rubrique' :
2728                                                case 'site' :
2729                                                        if ( $ChampExtra['traitement'] )
2730                                                                $datum_parsed = $ChampExtra['traitement']('[->'.$ChampExtra['type'].$datum_raw.']');
2731                                                        else { // il faut une requete de plus
2732                                                                $datum_parsed = sql_getfetsel($ChampExtra['type']=='auteur'?'nom':'titre', "spip_$ChampExtra[type]s", "id_$ChampExtra[type]=".intval($datum_raw) );
2733                                                        }
2734                                                        break;
2735                                                case 'auteurs' :
2736                                                        if ( $ChampExtra['traitement'] ) {
2737                                                                $valeurs = explode($datum_raw, ',');
2738                                                                foreach ($valeurs as $rang=>$valeur)
2739                                                                        $valeurs[$rang] = '[->auteur'.$valeurs[$rang].']';
2740                                                                $datum_parsed = implode(';', $valeurs);
2741                                                        } else { // il faut une requete de plus
2742                                                                $valeurs = sql_fetchall('nom', "spip_auteurs", "id_auteur IN (".sql_quote($datum_raw).')' );
2743                                                                $datum_parsed = implode(';', $valeurs);
2744                                                        }
2745                                                        break;
2746                                                case 'bloc' : // "<textarea...>...</textarea>"
2747                                                case 'ligne' : // "<input type='text' .../>"
2748                                                default :
2749                                                        $ChampExtra['traitement']?$ChampExtra['traitement']($datum_raw):$datum_raw;
2750                                        }
2751                                        $champsExtrasVoulus[$ChampExtra['champ']] = array( $label, $print, $datum );
2752                                } else {
2753                                        $champsExtrasVoulus[$ChampExtra['champ']] = $label;
2754                                }
2755                }
2756        }
2757        return $champsExtrasVoulus;
2758}
2759
2760/**
2761 * Encapsulation de _T()
2762 *
2763 * @param string $chaine
2764 *   Chaine de langue avec eventuellement le prefixe "asso" omis
2765 * @return string
2766 *   Libelle localise
2767 */
2768function association_langue($chaine) {
2769        if ( is_string($chaine) ) {
2770                $head = $chaine;
2771                $tail = array();
2772        } elseif ( is_array($chaine) ) {
2773                $head = array_shift($chaine);
2774                $tail = $chaine;
2775        } else
2776                return '';
2777        return _T((strpos($head,':') ? '' : 'asso:').$head, $tail );
2778}
2779
2780/** @} */
2781
2782
2783// pour executer les squelettes comportant la balise Meta
2784include_spip('balise/meta');
2785
2786// charger les metas donnees
2787$inc_meta = charger_fonction('meta', 'inc'); // inc_version l'a deja chargee
2788$inc_meta('association_metas');
2789
2790
2791
2792?>
Note: See TracBrowser for help on using the repository browser.