[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / plugins-dist / textwheel / inc / notes.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2016 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * Gestion des notes de bas de page
15 *
16 * @package SPIP\Textwheel\Notes
17 **/
18
19 if (!defined("_ECRIRE_INC_VERSION")) {
20 return;
21 }
22
23 //
24 // Notes de bas de page
25 //
26 if (!defined('_NOTES_OUVRE_REF')) {
27 define('_NOTES_OUVRE_REF', '<span class="spip_note_ref">&nbsp;[');
28 }
29 if (!defined('_NOTES_FERME_REF')) {
30 define('_NOTES_FERME_REF', ']</span>');
31 }
32 if (!defined('_NOTES_OUVRE_NOTE')) {
33 define('_NOTES_OUVRE_NOTE', '<span class="spip_note_ref">[');
34 }
35 if (!defined('_NOTES_FERME_NOTE')) {
36 define('_NOTES_FERME_NOTE', ']&nbsp;</span>');
37 }
38 if (!defined('_NOTES_RACCOURCI')) {
39 define('_NOTES_RACCOURCI', ',\[\[(\s*(<([^>\'"]*)>)?(.*?))\]\],msS');
40 }
41
42
43 /**
44 * Empile ou dépile des notes de bas de page
45 *
46 * Point d'entrée pour la gestion des notes.
47 *
48 * @note
49 * C'est stocké dans la globale `$les_notes`, mais pas besoin de le savoir
50 * @param bool|string|array $arg
51 * Argument :
52 *
53 * - true : empiler l'etat courant, initialiser un nouvel état
54 * - false : restaurer l'état précédent, dénonce un état courant perdu
55 * - chaîne : on y recherche les notes et on les renvoie en tableau
56 * - tableau : texte de notes à rajouter dans ce qu'on a déjà
57 *
58 * Ce dernier cas retourne la composition totale, en particulier,
59 * envoyer un tableau vide permet de tout récupérer.
60 * @param string $operation
61 * En complément du format attendu dans `$arg`, on indique ici
62 * le type d'oopétation à réaliser (traiter | empiler | depiler |
63 * sauver_etat | restaurer_etat | contexter_cache)
64 * @param bool $ignorer_autobr
65 * True pour ne pas prendre en compte les retours à la ligne comme
66 * des tags br (mais 2 à la suite font un paragraphe tout de même).
67 * @return string|array
68 **/
69 function inc_notes_dist($arg, $operation = 'traiter', $ignorer_autobr = false) {
70 static $pile = array();
71 static $next_marqueur = 1;
72 static $marqueur = 1;
73 global $les_notes, $compt_note, $notes_vues;
74 switch ($operation) {
75 case 'traiter':
76 if (is_array($arg)) {
77 return traiter_les_notes($arg, $ignorer_autobr);
78 } else {
79 return traiter_raccourci_notes($arg, $marqueur > 1 ? $marqueur : '');
80 }
81 break;
82 case 'empiler':
83 if ($compt_note == 0) // si le marqueur n'a pas encore ete utilise, on le recycle dans la pile courante
84 {
85 array_push($pile, array(@$les_notes, @$compt_note, $notes_vues, 0));
86 } else {
87 // sinon on le stocke au chaud, et on en cree un nouveau
88 array_push($pile, array(@$les_notes, @$compt_note, $notes_vues, $marqueur));
89 $next_marqueur++; // chaque fois qu'on rempile on incremente le marqueur general
90 $marqueur = $next_marqueur; // et on le prend comme marqueur courant
91 }
92 $les_notes = '';
93 $compt_note = 0;
94 break;
95 case 'depiler':
96 #$prev_notes = $les_notes;
97 if (strlen($les_notes)) {
98 spip_log("notes perdues");
99 }
100 // si le marqueur n'a pas servi, le liberer
101 if (!strlen($les_notes) and $marqueur == $next_marqueur) {
102 $next_marqueur--;
103 }
104 // on redepile tout suite a une fin d'inclusion ou d'un affichage des notes
105 list($les_notes, $compt_note, $notes_vues, $marqueur) = array_pop($pile);
106 #$les_notes .= $prev_notes;
107 // si pas de marqueur attribue, on le fait
108 if (!$marqueur) {
109 $next_marqueur++; // chaque fois qu'on rempile on incremente le marqueur general
110 $marqueur = $next_marqueur; // et on le prend comme marqueur courant
111 }
112 break;
113 case 'sauver_etat':
114 if ($compt_note or $marqueur > 1 or $next_marqueur > 1) {
115 return array($les_notes, $compt_note, $notes_vues, $marqueur, $next_marqueur);
116 } else {
117 return '';
118 } // rien a sauver
119 break;
120 case 'restaurer_etat':
121 if ($arg and is_array($arg)) // si qqchose a restaurer
122 {
123 list($les_notes, $compt_note, $notes_vues, $marqueur, $next_marqueur) = $arg;
124 }
125 break;
126 case 'contexter_cache':
127 if ($compt_note or $marqueur > 1 or $next_marqueur > 1) {
128 return array("$compt_note:$marqueur:$next_marqueur");
129 } else {
130 return '';
131 }
132 break;
133 case 'reset_all': // a n'utiliser qu'a fins de test
134 if (strlen($les_notes)) {
135 spip_log("notes perdues [reset_all]");
136 }
137 $pile = array();
138 $next_marqueur = 1;
139 $marqueur = 1;
140 $les_notes = '';
141 $compt_note = 0;
142 $notes_vues = array();
143 break;
144 }
145 }
146
147
148 function traiter_raccourci_notes($letexte, $marqueur_notes) {
149 global $compt_note, $notes_vues;
150
151 if (strpos($letexte, '[[') === false
152 or !preg_match_all(_NOTES_RACCOURCI, $letexte, $m, PREG_SET_ORDER)
153 ) {
154 return array($letexte, array());
155 }
156
157 // quand il y a plusieurs series de notes sur une meme page
158 $mn = !$marqueur_notes ? '' : ($marqueur_notes . '-');
159 $mes_notes = array();
160 foreach ($m as $r) {
161 list($note_source, $note_all, $ref, $nom, $note_texte) = $r;
162
163 // reperer une note nommee, i.e. entre chevrons
164 // On leve la Confusion avec une balise en regardant
165 // si la balise fermante correspondante existe
166 // Cas pathologique: [[ <a> <a href="x">x</a>]]
167
168 if (!(isset($nom) and $ref
169 and ((strpos($note_texte, '</' . $nom . '>') === false)
170 or preg_match(",<$nom\W.*</$nom>,", $note_texte)))
171 ) {
172 $nom = ++$compt_note;
173 $note_texte = $note_all;
174 }
175
176 // eliminer '%' pour l'attribut id
177 $ancre = $mn . str_replace('%', '_', rawurlencode($nom));
178
179 // ne mettre qu'une ancre par appel de note (XHTML)
180 if (!isset($notes_vues[$ancre])) {
181 $notes_vues[$ancre] = 0;
182 }
183 $att = ($notes_vues[$ancre]++) ? '' : " id='nh$ancre'";
184
185 // creer le popup 'title' sur l'appel de note
186 // propre est couteux => nettoyer_raccourcis_typo
187 if ($title = supprimer_tags(nettoyer_raccourcis_typo($note_texte))) {
188 $title = " title='" . couper($title, 80) . "'";
189 }
190
191 // ajouter la note aux notes precedentes
192 if ($note_texte) {
193 $mes_notes[] = array($ancre, $nom, $note_texte);
194 }
195
196 // dans le texte, mettre l'appel de note a la place de la note
197 if ($nom) {
198 $nom = _NOTES_OUVRE_REF . "<a href='#nb$ancre' class='spip_note' rel='appendix'$title$att>$nom</a>" . _NOTES_FERME_REF;
199 }
200
201 $pos = strpos($letexte, $note_source);
202 $letexte = rtrim(substr($letexte, 0, $pos), ' ')
203 . code_echappement($nom)
204 . substr($letexte, $pos + strlen($note_source));
205
206 }
207
208 return array($letexte, $mes_notes);
209 }
210
211
212 // https://code.spip.net/@traiter_les_notes
213 function traiter_les_notes($notes, $ignorer_autobr) {
214 $mes_notes = '';
215 if ($notes) {
216 $title = _T('info_notes');
217 foreach ($notes as $r) {
218 list($ancre, $nom, $texte) = $r;
219 $atts = " href='#nh$ancre' class='spip_note' title='$title $ancre' rev='appendix'";
220 $mes_notes .= "\n\n"
221 . "<div id='nb$ancre'><p" . ($GLOBALS['class_spip'] ? " class='spip_note'" : "") . ">"
222 . code_echappement($nom
223 ? _NOTES_OUVRE_NOTE . "<a" . $atts . ">$nom</a>" . _NOTES_FERME_NOTE
224 : '')
225 . trim($texte)
226 . '</div>';
227 }
228 if ($ignorer_autobr) {
229 $mes_notes = _AUTOBR_IGNORER . $mes_notes;
230 }
231 $mes_notes = propre($mes_notes);
232 }
233
234 return ($GLOBALS['les_notes'] .= $mes_notes);
235 }