source: spip-zone/_plugins_/table_matieres/trunk/tablematieres_fonctions.php @ 73533

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

Un log en moins et micro refactoring du fichier de fonctions

On revoit le js de la table des matières flottante qui devrait mieux fonctionner avec ancres douces et être plus stable (à tester)

Version 2.2.1

File size: 8.3 KB
Line 
1<?php
2
3if (!defined("_ECRIRE_INC_VERSION")) return;
4
5// tester la presence de CFG
6$tm = @unserialize($GLOBALS['meta']['table_matieres']);
7
8define('_AUTO_ANCRE', isset($tm['auto']) ? $tm['auto'] : 'oui');
9define('_LG_ANCRE', isset($tm['lg']) ? $tm['lg'] : 35);
10define('_SEP_ANCRE', isset($tm['sep']) ? $tm['sep'] : '-');
11define('_MIN_ANCRE', isset($tm['min']) ? $tm['min'] : 3);
12define('_RETOUR_TDM', '<a href="#tdm" class="tdm"><img src="' .
13        find_in_path('images/tdm.png') . 
14        '" /></a>');
15
16/**
17 * Fonction d'API.
18 *
19 * Elle reçoit un texte ayant encore les raccourcis SPIP
20 * et donc les codes des éventuels intertitres tel que "{{{ intertitre }}}".
21 *
22 * Elle ajoute une table des matières en entête du texte (par défaut)
23 * Et retourne le texte avec les intertitres complétés d'un lien de retour
24 * vers le sommaire automatique.
25 *
26 * En option, on peut demander à la fonction de ne retourner
27 * QUE la table des matières.
28 *
29 * @param string $texte Texte en entrée
30 * @param string $retourner Retourner quoi ? (tout, tdm, texte)
31 * @return string       Texte avec une table des matières
32 */
33function table_matieres($texte, $retourner = 'tout') {
34        static $table_matieres = false;
35
36        if (!$texte) {
37                return $texte;
38        }
39        if (!$table_matieres)
40                $table_matieres = charger_fonction('table_matieres', 'inc');
41       
42        return $table_matieres($texte, $retourner);
43}
44
45/**
46 * Fonction principale du plugin
47 * cf. description sur la fonction d'appel table_matieres()
48 *
49 * @param string $texte Texte en entrée
50 * @param bool $retourner Retourner quoi ?
51 *              - 'tout' : tout (tdm + texte)
52 *              - 'tdm' : la table des matieres
53 *              - 'texte' : le texte (et les ancres)
54 * @return string       Texte avec une table des matières
55 */
56function inc_table_matieres_dist($texte, $retourner = 'tout') {
57
58        // sauvegarde pour ne pas calculer 2 fois les mêmes choses
59        static $textes = array();
60        $md5 = md5($texte);
61
62        if (!in_array($retourner, array('tout', 'tdm', 'texte'))) {
63                $retourner = 'tout';
64                spip_log("Erreur de parametre sur la fonction table_matieres.");
65        }
66       
67        // deja calculé ? on s'en retourne.
68        if (isset($textes[$md5])) {
69                if ($retourner == 'tout') {
70                        return $textes[$md5]['tdm'] . $textes[$md5]['texte'];
71                }
72                return $textes[$md5][$retourner];
73        }
74
75        // protection des expressions qui ne font pas partie de la table des matières
76        //
77        // le 3e à true pour ne pas utiliser les fonctions d'echappement predefinis
78        // et garder les textes tels quels (ex: <code><balise></code>)
79        // sinon la transformation est effectuee 2 fois.
80        $texte_protege = echappe_html($texte, 'TDM', true);
81
82        // vider les caches d'intertitres trouves
83        tdm_vider_intertitres();
84       
85        // dans un premier temps, on traverse le texte à la recherche d'intertitres.
86        // et pour chaque intertitre trouvé, on ajoute un marqueur qui
87        // permettra d'ajouter un lien de retour vers l'intertitre.
88        // On réalise l'opétation pour chaque type d'intertitre : {{{}}}, ===, {2{...
89        // si leurs définitions sont présentes.
90        foreach( tdm_remplacements_intertitres() as $regexp => $callback ) {
91                $texte_protege = preg_replace_callback($regexp, $callback, $texte_protege);
92        }
93
94        // si l'on a trouvé moins d'intertitres que le minimum vital (configurable)
95        // on rétablit le texte d'origine et on s'en va !
96        $intertitres = tdm_get_intertitres();
97        if ( count($intertitres) < _MIN_ANCRE ) {
98                $textes[$md5] = array(
99                        'tdm' => '',
100                        'texte' => $texte
101                );
102                if ($retourner == 'tout') {
103                        return $textes[$md5]['tdm'] . $textes[$md5]['texte'];
104                }
105                return $textes[$md5][$retourner];
106        }
107       
108        // dévérouillage des protections
109        $texte = echappe_retour($texte_protege, 'TDM');
110
111        // calculer la table des matières
112        $tdm = tdm_generer_table_des_matieres($intertitres);
113
114        // ajouter les icones de retour vers la table des matieres
115        $texte = tdm_ajouter_liens_retour_table_matieres($texte);
116
117        // sauver
118        $textes[$md5] = array(
119                'tdm' => $tdm,
120                'texte' => $texte
121        );
122
123        // c'est fini !
124        if ($retourner == 'tout') {
125                return $textes[$md5]['tdm'] . $textes[$md5]['texte'];
126        }
127        return $textes[$md5][$retourner];
128}
129
130/**
131 * Retourne la liste des raccourcis d'intertitres / fonction de remplacements
132 * pour la recherche d'intertitres.
133 *
134 * Cette fonction pourra être étendue
135 * par un pipeline ou une globale
136 *
137 * @return arrray  expression régulière / fonction de remplacement
138 */
139function tdm_remplacements_intertitres() {
140        return array(
141                "/{{{(.*)}}}/UmsS" => 'tdm_remplacement_raccourcis_standard_callback'
142        );
143}
144
145/**
146 * Intertitre en entrée.
147 * L'analyse, stocke l'information et retourne l'intertitre complété
148 *
149 * @param string $matches       Captures de l'expression régulière
150 * @return l'intertitre complété du code de lien de retour.
151 */
152function tdm_remplacement_raccourcis_standard_callback($matches) {
153        list($titre, $url) = tdm_calculer_titre( $matches[1] ); // intertitre dans /1
154        $url = tdm_stocker_intertitre($url, $titre);
155        return '{{{ [' . $url . '<-] ' . $matches[1] . ' @@RETOUR_TDM@@ }}}';
156}
157
158/**
159 * Calcule le titre et l'url de l'ancre
160 * a partir d'un intertitre donné
161 *
162 * @param string $intertitre
163 * @return array titre/url
164 */
165function tdm_calculer_titre($intertitre) {
166        $titre = supprimer_tags(typo($intertitre));
167        $titre = preg_replace(",\n[_\s]*,", " ", $titre);
168        $url = translitteration($titre);
169        $url = @preg_replace(',[[:punct:][:space:]]+,u', ' ', $url);
170
171        // S'il reste des caracteres non latins, utiliser l'id a la place
172        if (preg_match(",[^a-zA-Z0-9 ],", $url)) {
173                $url = "ancre$cId";
174        }
175        else {
176                $mots = explode(' ', $url);
177                $url = '';
178                foreach ($mots as $mot) {
179                        if (!$mot) continue;
180                        $url2 = $url._SEP_ANCRE.$mot;
181                        if (strlen($url2) > _LG_ANCRE) {
182                                break;
183                        }
184                        $url = $url2;
185                }
186                $url = substr($url, 1);
187                if (strlen($url) < 2) $url = "ancre$cId";
188        }
189
190        return array($titre, strtolower($url));
191}
192
193/**
194 * Remet à zéro la liste des intertitres trouvés
195 */
196function tdm_vider_intertitres() {
197        tdm_stocker_intertitre('', '', true);
198}
199
200/**
201 * Retourne la liste des intertitres trouvés
202 * @return array        Liste des intertitres (url/titre)
203 */
204function tdm_get_intertitres() {
205        return tdm_stocker_intertitre('');
206}
207
208/**
209 * Stocke les intertitres trouves.
210 * Si une url est deja presente, on identifie l'url d'un numero
211 *
212 * Passer une url vide pour recuperer le tableau.
213 *
214 * @param string $url   url de l'ancre
215 * @param string $titre titre de l'ancre
216 * @param bool $vider   effacer les sauvegarde ?
217 * @return
218 */
219function tdm_stocker_intertitre($url='', $titre='', $vider = false) {
220        static $table = array();
221        static $cpt = 0;
222        if($vider_table) return ($table = array());
223        if (!$url) return $table;
224        $cpt++;
225        $url = array_key_exists($url, $table) ? $url.$cpt : $url;
226        $table[$url] = $titre;
227        return $url;
228}
229
230/**
231 * Remplace les @@RETOUR_TDM@@ laissés par les callback de recherche d'intertitres
232 * par le lien de retour correspondant
233 *
234 * @param string $texte Texte d'entrée
235 * @return string Texte avec retours remplacés
236 */
237function tdm_ajouter_liens_retour_table_matieres($texte) {
238       
239        // prendre en compte la langue en cours
240        $_RETOUR_TDM = preg_replace(
241                ',<img,i',
242                '<img alt="' . _T('tdm:retour_table_matiere')
243                .'" title="' . _T('tdm:retour_table_matiere') . '"',
244                _RETOUR_TDM);
245
246        if (!test_espace_prive() AND TDM_JAVASCRIPT AND !_AJAX)# crayons
247                $_RETOUR_TDM = '';
248
249        return str_replace('@@RETOUR_TDM@@', $_RETOUR_TDM, $texte);
250}
251
252/**
253 * Générer une table des matieres a partir du tableau
254 * d'intertitres donnes
255 *
256 * @param array couples liens/intertitres
257 * @return string       Code HTML de la table des matieres
258 */
259function tdm_generer_table_des_matieres($intertitres) {
260        // generer un code HTML
261        $code = "";
262        foreach ($intertitres as $url=>$titre) {
263                $code .= "<li><a href='#$url'>$titre</a></li>\n";
264        }
265
266        // code HTML de la table des matieres
267        $_table = recuperer_fond('modeles/table_matieres', array(
268                'code' => $code,
269                'tableau'=>$intertitres
270        ));
271
272        if (!test_espace_prive() AND TDM_JAVASCRIPT AND $_table 
273                AND !_AJAX){ # crayons
274                $_table = inserer_attribut('<div class="encart"></div>',
275                        'rel', $_table);
276        }
277        return $_table;
278}
279
280/**
281 * Balise #TABLE_MATIERES
282 * Affiche la table des matieres à l'endroit indique
283 * A utiliser dans une boucle Articles
284 */
285function balise_TABLE_MATIERES_dist($p) {
286        $b = $p->nom_boucle ? $p->nom_boucle : $p->descr['id_mere'];
287        if ($b === '') {
288                erreur_squelette(
289                        _T('zbug_champ_hors_boucle',
290                                array('champ' => '#TABLE_MATIERES')
291                        ), $p->id_boucle);
292                $p->code = "''";
293        } else {
294                $_texte = champ_sql('texte', $p);
295                $p->code = "$_texte";
296        }
297        return $p;
298}
299
300?>
Note: See TracBrowser for help on using the repository browser.