3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2016 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
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 \***************************************************************************/
14 * Gestion des notes de bas de page
16 * @package SPIP\Textwheel\Notes
19 if (!defined("_ECRIRE_INC_VERSION")) {
24 // Notes de bas de page
26 if (!defined('_NOTES_OUVRE_REF')) {
27 define('_NOTES_OUVRE_REF', '<span class="spip_note_ref"> [');
29 if (!defined('_NOTES_FERME_REF')) {
30 define('_NOTES_FERME_REF', ']</span>');
32 if (!defined('_NOTES_OUVRE_NOTE')) {
33 define('_NOTES_OUVRE_NOTE', '<span class="spip_note_ref">[');
35 if (!defined('_NOTES_FERME_NOTE')) {
36 define('_NOTES_FERME_NOTE', '] </span>');
38 if (!defined('_NOTES_RACCOURCI')) {
39 define('_NOTES_RACCOURCI', ',\[\[(\s*(<([^>\'"]*)>)?(.*?))\]\],msS');
44 * Empile ou dépile des notes de bas de page
46 * Point d'entrée pour la gestion des notes.
49 * C'est stocké dans la globale `$les_notes`, mais pas besoin de le savoir
50 * @param bool|string|array $arg
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à
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
69 function inc_notes_dist($arg, $operation = 'traiter', $ignorer_autobr = false) {
70 static $pile = array();
71 static $next_marqueur = 1;
73 global $les_notes, $compt_note, $notes_vues;
77 return traiter_les_notes($arg, $ignorer_autobr);
79 return traiter_raccourci_notes($arg, $marqueur > 1 ?
$marqueur : '');
83 if ($compt_note == 0) // si le marqueur n'a pas encore ete utilise, on le recycle dans la pile courante
85 array_push($pile, array(@$les_notes, @$compt_note, $notes_vues, 0));
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
96 #$prev_notes = $les_notes;
97 if (strlen($les_notes)) {
98 spip_log("notes perdues");
100 // si le marqueur n'a pas servi, le liberer
101 if (!strlen($les_notes) and $marqueur == $next_marqueur) {
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
109 $next_marqueur++
; // chaque fois qu'on rempile on incremente le marqueur general
110 $marqueur = $next_marqueur; // et on le prend comme marqueur courant
114 if ($compt_note or $marqueur > 1 or $next_marqueur > 1) {
115 return array($les_notes, $compt_note, $notes_vues, $marqueur, $next_marqueur);
120 case 'restaurer_etat':
121 if ($arg and is_array($arg)) // si qqchose a restaurer
123 list($les_notes, $compt_note, $notes_vues, $marqueur, $next_marqueur) = $arg;
126 case 'contexter_cache':
127 if ($compt_note or $marqueur > 1 or $next_marqueur > 1) {
128 return array("$compt_note:$marqueur:$next_marqueur");
133 case 'reset_all': // a n'utiliser qu'a fins de test
134 if (strlen($les_notes)) {
135 spip_log("notes perdues [reset_all]");
142 $notes_vues = array();
148 function traiter_raccourci_notes($letexte, $marqueur_notes) {
149 global $compt_note, $notes_vues;
151 if (strpos($letexte, '[[') === false
152 or !preg_match_all(_NOTES_RACCOURCI
, $letexte, $m, PREG_SET_ORDER
)
154 return array($letexte, array());
157 // quand il y a plusieurs series de notes sur une meme page
158 $mn = !$marqueur_notes ?
'' : ($marqueur_notes . '-');
159 $mes_notes = array();
161 list($note_source, $note_all, $ref, $nom, $note_texte) = $r;
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>]]
168 if (!(isset($nom) and $ref
169 and ((strpos($note_texte, '</' . $nom . '>') === false)
170 or preg_match(",<$nom\W.*</$nom>,", $note_texte)))
172 $nom = ++
$compt_note;
173 $note_texte = $note_all;
176 // eliminer '%' pour l'attribut id
177 $ancre = $mn . str_replace('%', '_', rawurlencode($nom));
179 // ne mettre qu'une ancre par appel de note (XHTML)
180 if (!isset($notes_vues[$ancre])) {
181 $notes_vues[$ancre] = 0;
183 $att = ($notes_vues[$ancre]++
) ?
'' : " id='nh$ancre'";
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) . "'";
191 // ajouter la note aux notes precedentes
193 $mes_notes[] = array($ancre, $nom, $note_texte);
196 // dans le texte, mettre l'appel de note a la place de la note
198 $nom = _NOTES_OUVRE_REF
. "<a href='#nb$ancre' class='spip_note' rel='appendix'$title$att>$nom</a>" . _NOTES_FERME_REF
;
201 $pos = strpos($letexte, $note_source);
202 $letexte = rtrim(substr($letexte, 0, $pos), ' ')
203 . code_echappement($nom)
204 . substr($letexte, $pos +
strlen($note_source));
208 return array($letexte, $mes_notes);
212 // https://code.spip.net/@traiter_les_notes
213 function traiter_les_notes($notes, $ignorer_autobr) {
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'";
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
228 if ($ignorer_autobr) {
229 $mes_notes = _AUTOBR_IGNORER
. $mes_notes;
231 $mes_notes = propre($mes_notes);
234 return ($GLOBALS['les_notes'] .= $mes_notes);