Newer
Older
"($message)", $letexte);
// traite les modeles (dans la fonction typo), en remplacant
// le raccourci <modeleN|parametres> par la page calculee a
// partir du squelette modeles/modele.html
// Le nom du modele doit faire au moins trois caracteres (evite <h2>)
// Si $doublons==true, on repere les documents sans calculer les modeles
// mais on renvoie les params (pour l'indexation par le moteur de recherche)
// http://doc.spip.org/@traiter_modeles
define('_RACCOURCI_MODELE',
'(<([a-z_-]{3,})' # <modele
.'\s*([0-9]*)\s*' # id
.'([|](?:<[^<>]*>|[^>])*?)?' # |arguments (y compris des tags <...>)
.'\s*/?'.'>)' # fin du modele >
.'\s*(<\/a>)?' # eventuel </a>
);
define('_RACCOURCI_MODELE_DEBUT', '@^' . _RACCOURCI_MODELE .'@is');
function traiter_modeles($texte, $doublons=false, $echap='', $connect='') {
// detecter les modeles (rapide)
Fil
a validé
if (preg_match_all('/<[a-z_-]{3,}\s*[0-9|]+/iS',
$texte, $matches, PREG_SET_ORDER)) {
include_spip('public/assembler');
foreach ($matches as $match) {
// Recuperer l'appel complet (y compris un eventuel lien)
Fil
a validé
// $regs : 1 => modele, 2 => type, 3 => id, 4 => params, 5 => a
$a = strpos($texte,$match[0]);
preg_match(_RACCOURCI_MODELE_DEBUT, substr($texte, $a), $regs);
Fil
a validé
if ($regs[5] AND preg_match(
',<a\s[^<>]*>\s*$,i', substr($texte, 0, $a), $r)) {
$lien = array(
extraire_attribut($r[0],'href'),
extraire_attribut($r[0],'class')
);
$a -= strlen($r[0]);
$cherche = $r[0].$regs[0];
} else {
$lien = false;
$cherche = $regs[1];
}
// calculer le modele
# hack articles_edit, breves_edit, indexation
if ($doublons)
$texte .= preg_replace(',[|][^|=]*,s',' ',$regs[4]);
# version normale
else {
$modele = inclure_modele($regs[2], $regs[3], $regs[4], $lien, $connect);
// le remplacer dans le texte
if ($modele !== false) {
$modele = protege_js_modeles($modele);
$rempl = code_echappement($modele, $echap);
$texte = substr($texte, 0, $a)
. $rempl
. substr($texte, $a+strlen($cherche));
}
// hack pour tout l'espace prive
if (((!_DIR_RESTREINT) OR ($doublons)) AND ($regs[3]) AND (in_array($regs[2],array('doc','emb','img'))))
$GLOBALS['doublons_documents_inclus'][] = $regs[3];
}
}
return $texte;
}
//
// Une fonction pour fermer les paragraphes ; on essaie de preserver
// des paragraphes indiques a la main dans le texte
// (par ex: on ne modifie pas un <p align='center'>)
//
// deuxieme argument : forcer les <p> meme pour un seul paragraphe
//
// http://doc.spip.org/@paragrapher
function paragrapher($letexte, $forcer=true) {
$letexte = trim($letexte);
if (!strlen($letexte))
return '';
if ($forcer OR (
strstr($letexte,'<') AND preg_match(',<p\b,iS',$letexte)
)) {
// Ajouter un espace aux <p> et un "STOP P"
// transformer aussi les </p> existants en <p>, nettoyes ensuite
$letexte = preg_replace(',</?p(\s([^>]*))?'.'>,iS', '<STOP P><p \2>',
'<p>'.$letexte.'<STOP P>');
// Fermer les paragraphes (y compris sur "STOP P")
$letexte = preg_replace(
',(<p\s.*)(</?(STOP P|'._BALISES_BLOCS.')[>[:space:]]),UimsS',
"\n\\1</p>\n\\2", $letexte);
// Supprimer les marqueurs "STOP P"
$letexte = str_replace('<STOP P>', '', $letexte);
// Reduire les blancs dans les <p>
renato
a validé
// Do not delete multibyte utf character just before </p> having last byte equal to whitespace
$u = ($GLOBALS['meta']['charset']=='utf-8' && test_pcre_unicode()) ? 'u':'S';
$letexte = preg_replace(
renato
a validé
',(<p(>|\s[^>]*)>)\s*|\s*(</p[>[:space:]]),'.$u.'i', '\1\3',
$letexte);
// Supprimer les <p xx></p> vides
$letexte = preg_replace(',<p\s[^>]*></p>\s*,iS', '',
// Renommer les paragraphes normaux
$letexte);
}
return $letexte;
}
//
// Raccourcis ancre [#ancre<-]
//
define('_RACCOURCI_ANCRE', "|\[#?([^][]*)<-\]|S");
function traiter_raccourci_ancre($letexte)
{
if (preg_match_all(_RACCOURCI_ANCRE, $letexte, $m, PREG_SET_ORDER))
foreach ($m as $regs)
$letexte = str_replace($regs[0],
'<a name="'.entites_html($regs[1]).'"></a>', $letexte);
return $letexte;
}
//
// Raccourcis automatiques [?SPIP] vers un glossaire
//
define('_RACCOURCI_GLOSSAIRE', "|\[\?+\s*([^][<>]+)\]|S");
function traiter_raccourci_glossaire($letexte)
{
static $glosateur = NULL, $subst = NULL;
if ($glosateur === NULL) {
$glosateur = tester_variable('url_glossaire_externe',
"http://@lang@.wikipedia.org/wiki/");
$subst = strpos($glosateur,"%s") !== false;
}
if (empty($glosateur)
OR !preg_match_all(_RACCOURCI_GLOSSAIRE, $letexte, $m, PREG_SET_ORDER))
return $letexte;
$glosateur = str_replace("@lang@", $GLOBALS['spip_lang'], $glosateur);
foreach ($m as $regs) {
list($tout, $terme) = $regs;
// Eviter les cas particulier genre "[?!?]"
if (preg_match(',^(.*\w\S*)\s*$,', $terme, $r)) {
$terme = $r[1];
$_terme = preg_replace(',\s+,', '_', $terme);
// faire sauter l'eventuelle partie "|bulle d'aide" du lien
// cf. http://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Conventions_sur_les_titres
$_terme = preg_replace(',[|].*,', '', $_terme);
if ($subst)
$url = str_replace("%s", rawurlencode($_terme), $glosateur);
else $url = $glosateur. $_terme;
list($terme, $bulle, $hlang) = traiter_raccourci_lien_atts($terme);
$url = traiter_raccourci_lien_lang($url, 'spip_glossaire', $terme, $hlang, $bulle);
$letexte = str_replace($tout, $url, $letexte);
}
}
return $letexte;
}
//
// Raccourcis liens [xxx->url]
// Note : complique car c'est ici qu'on applique typo(),
// et en plus on veut pouvoir les passer en pipeline
//
// Regexp des raccouris, aussi utilisee pour la fusion de sauvegarde Spip
define('_RACCOURCI_LIEN', ",\[([^][]*)->(>?)([^]]*)\],msS");
function expanser_liens($letexte, $connect='')
{
$inserts = array();
if (preg_match_all(_RACCOURCI_LIEN, $letexte, $matches, PREG_SET_ORDER)) {
$i = 0;
foreach ($matches as $regs) {
$inserts[++$i] = traiter_raccourci_lien($regs, $connect);
$letexte = str_replace($regs[0], "@@SPIP_ECHAPPE_LIEN_$i@@",
$letexte);
}
}
$letexte = corriger_typo(traiter_modeles($letexte, false, false, $connect));
foreach ($inserts as $i => $insert) {
$letexte = str_replace("@@SPIP_ECHAPPE_LIEN_$i@@", $insert, $letexte);
}
return $letexte;
}
//
// Inserer un lien a partir du preg_match du raccourci [xx->url]
// $regs:
// 0=>tout le raccourci
// 1=>texte (ou texte|hreflang ou texte|bulle ou texte|bulle{hreflang})
// 2=>double fleche (historiquement, liens ouvrants)
// 3=>url
// A terme, il faudrait tenir compte de $connect
Christian Lefebvre
a validé
// http://doc.spip.org/@traiter_raccourci_lien
function traiter_raccourci_lien($regs, $connect='') {
list(,$texte, ,$url) = $regs;
list($texte, $bulle, $hlang) = traiter_raccourci_lien_atts($texte);
list ($lien, $class, $texte, $lang) =
calculer_url($url, $texte, 'tout');
return traiter_raccourci_lien_lang($lien, $class, $texte, $hlang, $bulle, $connect);
}
function traiter_raccourci_lien_lang($lien, $class, $texte, $hlang, $bulle, $connect='')
{
// Si l'objet n'est pas de la langue courante, on ajoute hreflang
if (!$hlang AND $lang!=$GLOBALS['spip_lang'])
$hlang = $lang;
$lang = ($hlang ? ' hreflang="'.$hlang.'"' : '') . $bulle;
# Penser au cas [<imgXX|right>->URL]
# ceci s'execute heureusement avant les tableaux et leur "|".
# Attention, le texte initial est deja echappe mais pas forcement
# celui retourne par calculer_url.
$texte = typo($texte, true, $connect);
return "<a href=\"$lien\" class=\"$class\"$lang>$texte</a>";
}
// Repere dans la partie texte d'un raccourci [texte->...]
// la langue et la bulle eventuelles
function traiter_raccourci_lien_atts($texte) {
$bulle = $hlang = '';
// title et hreflang donnes par le raccourci ?
if (preg_match(',^(.*?)([|]([^<>]*?))?([{]([a-z_]+)[}])?$,', $texte, $m)) {
// |infobulle ?
$bulle = ' title="'.texte_backend($m[3]).'"';
// si c'est un code de langue connu, on met un hreflang
if (traduire_nom_langue($m[5]) <> $m[5]) {
$hlang = $m[5];
}
// sinon c'est un italique
else {
$m[1] .= $m[4];
}
// S'il n'y a pas de hreflang sous la forme {}, ce qui suit le |
// est peut-etre une langue
} else if (preg_match(',^[a-z_]+$,', $m[3])) {
// si c'est un code de langue connu, on met un hreflang
// mais on laisse le title (c'est arbitraire tout ca...)
if (traduire_nom_langue($m[3]) <> $m[3]) {
$hlang = $m[3];
}
}
}
$texte = $m[1];
return array($texte, $bulle, $hlang);
}
// Fonction pour les champs chapo commencant par =, redirection qui peut etre:
// 1. un raccourci Spip habituel (premier If) [texte->TYPEnnn]
// 2. un ultra raccourci TYPEnnn voire nnn (article) (deuxieme If)
// 3. une URL std
// renvoie une tableau structure comme ci-dessus mais sans calcul d'URL
// (cf fusion de sauvegardes)
define('_RACCOURCI_CHAPO', ',^(\W*)(\W*)(\w*\d+([?#].*)?)$,');
function chapo_redirige($chapo, $url=false)
{
if (!preg_match(_RACCOURCI_LIEN, $chapo, $m))
if (!preg_match(_RACCOURCI_CHAPO, $chapo, $m))
return $chapo;
return !$url ? $m[3] : calculer_url($m[3]);
}
function traiter_poesie($letexte)
{
if (preg_match_all(",<(poesie|poetry)>(.*)<\/(poesie|poetry)>,UimsS",
$letexte, $regs, PREG_SET_ORDER)) {
foreach ($regs as $reg) {
$lecode = preg_replace(",\r\n?,S", "\n", $reg[2]);
$lecode = preg_replace("/\n[\s]*\n/", "\n \n",$lecode);
$lecode = "<blockquote class=\"spip_poesie\">\n<div>".preg_replace("/\n+/", "</div>\n<div>", trim($lecode))."</div>\n</blockquote>\n\n";
$letexte = str_replace($reg[0], $lecode, $letexte);
}
}
return $letexte;
}
// Nettoie un texte, traite les raccourcis autre qu'URL, la typo, etc.
// http://doc.spip.org/@traiter_raccourcis
function traiter_raccourcis($letexte) {
static $remplace = NULL;
// Appeler les fonctions de pre_traitement
$letexte = pipeline('pre_propre', $letexte);
$letexte = traiter_poesie($letexte);
// Harmoniser les retours chariot
$letexte = preg_replace(",\r\n?,S", "\n", $letexte);
// Recuperer les paragraphes HTML
$letexte = preg_replace(',<p\b,iS', "\n\n\\0", $letexte);
$letexte = preg_replace(',</p\b,iS', "\\0\n\n", $letexte);
$letexte = traiter_raccourci_glossaire($letexte);
$letexte = traiter_raccourci_ancre($letexte);
list($letexte, $mes_notes) = traite_raccourci_notes($letexte);
// A present on introduit des attributs class_spip*
// Init de leur valeur et connexes au premier appel
if (!$remplace) $remplace = traiter_variables_sales();
// Tableaux
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
// ne pas oublier les tableaux au debut ou a la fin du texte
$letexte = preg_replace(",^\n?[|],S", "\n\n|", $letexte);
$letexte = preg_replace(",\n\n+[|],S", "\n\n\n\n|", $letexte);
$letexte = preg_replace(",[|](\n\n+|\n?$),S", "|\n\n\n\n", $letexte);
if (preg_match_all(',[^|](\n[|].*[|]\n)[^|],UmsS', $letexte,
$regs, PREG_SET_ORDER))
foreach ($regs as $tab) {
$letexte = str_replace($tab[1], traiter_tableau($tab[1]), $letexte);
}
$letexte = "\n".trim($letexte);
// les listes
if (strpos($letexte,"\n-*")!==false OR strpos($letexte,"\n-#")!==false)
$letexte = traiter_listes($letexte);
// Proteger les caracteres actifs a l'interieur des tags html
$protege = "{}_-";
$illegal = "\x1\x2\x3\x4";
if (preg_match_all(",</?[a-z!][^<>]*[".preg_quote($protege)."][^<>]*>,imsS",
$letexte, $regs, PREG_SET_ORDER)) {
foreach ($regs as $reg) {
$insert = $reg[0];
// hack: on transforme les caracteres a proteger en les remplacant
// par des caracteres "illegaux". (cf corriger_caracteres())
$insert = strtr($insert, $protege, $illegal);
$letexte = str_replace($reg[0], $insert, $letexte);
}
}
// autres raccourcis
$puce = (strpos($letexte, "\n- ") == false) ? '' : definir_puce();
$puce_rac = array("/\n-- */S", "/\n- */S");
$puce_long = array("\n<br />— ", "\n<br />$puce ");
$letexte = preg_replace($puce_rac, $puce_long, $letexte);
$letexte = preg_replace($remplace[0], $remplace[1], $letexte);
$letexte = preg_replace("@^ <br />@S", "", $letexte);
// Retablir les caracteres proteges
$letexte = strtr($letexte, $illegal, $protege);
// Fermer les paragraphes ; mais ne pas en creer si un seul
$letexte = paragrapher($letexte, $GLOBALS['toujours_paragrapher']);
// Appeler les fonctions de post-traitement
$letexte = pipeline('post_propre', $letexte);
if ($mes_notes) traiter_les_notes($mes_notes);
return $letexte;
}
//
// Notes de bas de page
//
function traite_raccourci_notes($letexte)
{
global $compt_note, $marqueur_notes, $les_notes;
global $ouvre_ref, $ferme_ref, $ouvre_note, $ferme_note; #static ok
static $notes_vues = NULL;
if ($notes_vues === NULL) {
$ouvre_ref = tester_variable('ouvre_ref', ' [');
$ferme_ref = tester_variable('ferme_ref', ']');
$ouvre_note = tester_variable('ouvre_note', '[');
$ferme_note = tester_variable('ferme_note', '] ');
$les_notes = tester_variable('les_notes', '');
$compt_note = tester_variable('compt_note', 0);
$notes_vues === array();
}
$mes_notes = '';
$regexp = ', *\[\[(.*?)\]\],msS';
if (preg_match_all($regexp, $letexte, $matches, PREG_SET_ORDER))
foreach ($matches as $regs) {
if (preg_match(",^<([^>'\"]*)>,", ltrim($note_texte), $r)
AND strpos($note_texte, '</' . $r[1] .'>') === false) {
$num_note = $r[1];
$note_texte = substr_replace(ltrim($note_texte), '', 0, strlen($r[0]));
if ($marqueur_notes) // quand il y a plusieurs series
// de notes sur une meme page
$mn = $marqueur_notes.'-';
$ancre = $mn.rawurlencode($num_note);
// ne mettre qu'une ancre par appel de note (XHTML)
if (!$notes_vues[$ancre]++)
$name_id = " name=\"nh$ancre\" id=\"nh$ancre\"";
else
$name_id = "";
$lien = "<a href=\"#nb$ancre\"$name_id class=\"spip_note\" rel=\"footnote\">";
// creer le popup 'title' sur l'appel de note
if ($title = supprimer_tags(propre($note_texte))) {
$title = couper($title,80);
$lien = inserer_attribut($lien, 'title', $title);
$insert = "$ouvre_ref$lien$num_note</a>$ferme_ref";
// on l'echappe
$insert = code_echappement($insert);
$appel = "$ouvre_note<a href=\"#nh$ancre\" name=\"nb$ancre\" class=\"spip_note\" title=\"" . _T('info_notes') . " $ancre\" rev=\"footnote\">$num_note</a>$ferme_note";
// l'ajouter "tel quel" (echappe) dans les notes
if ($mes_notes)
$mes_notes .= "\n\n";
$mes_notes .= code_echappement($appel) . $note_texte;
}
// dans le texte, mettre l'appel de note a la place de la note
$pos = strpos($letexte, $note_source);
$letexte = substr($letexte, 0, $pos) . $insert
. substr($letexte, $pos + strlen($note_source));
Fil
a validé
}
return array($letexte, $mes_notes);
esj
a validé
}
// http://doc.spip.org/@traiter_les_notes
function traiter_les_notes($mes_notes) {
$mes_notes = propre('<p>'.$mes_notes);
if ($GLOBALS['class_spip'])
$mes_notes = str_replace('<p class="spip">', '<p class="spip_note">', $mes_notes);
$GLOBALS['les_notes'] .= $mes_notes;
esj
a validé
}
// Filtre a appliquer aux champs du type #TEXTE*
// http://doc.spip.org/@propre
function propre($t, $connect='') {
return !$t ? '' :
echappe_retour_modeles(
traiter_raccourcis(
expanser_liens(echappe_html($t),$connect)));