Changement de la gestion des URL spéciales # # 3.2.1 # Olivier # => Changement syntaxe des macros # # 3.2 # Olivier # => Changement de fonctionnement des macros # => Passage de fonctions externes pour les macros et les mots wiki # # 3.1d # Jérôme Lipowicz # => antispam # Olivier # => centrage d'image # # 3.1c # Olivier # => Possibilité d'échaper les | dans les marqueurs avec \ # # 3.1b # Nicolas Chachereau # => Changement de regexp pour la correction syntaxique # # 3.1a # Olivier # => Bug du Call-time pass-by-reference # # 3.1 # Olivier # => Ajout des macros «««..»»» # => Ajout des blocs vides øøø # => Ajout du niveau de titre paramétrable # => Option de blocage du parseur dans les
# => Titres au format setext (experimental, désactivé) # # 3.0 # Olivier => Récriture du parseur inline, plus d'erreur XHTML # => Ajout d'une vérification d'intégrité pour les listes # => Les acronymes sont maintenant dans un fichier texte # => Ajout d'un tag images ((..)), del --..-- et ins ++..++ # => Plus possible de faire des liens JS [lien|javascript:...] # => Ajout des notes de bas de page §§...§§ # => Ajout des mots wiki # # 2.5 # Olivier => Récriture du code, plus besoin du saut de ligne entre blocs != # # 2.0 # Stephanie => correction des PCRE et ajout de fonctionnalités # Mathieu => ajout du strip-tags, implementation des options, reconnaissance automatique d'url, etc. # Olivier => chagement de active_link en active_urls # => ajout des options pour les blocs # => intégration de l'aide dans le code, avec les options # => début de quelque chose pour la reconnaissance auto d'url (avec Mat) # TODO : # Mathieu => active_wiki_urls (modifier wikiParseUrl ?) # => active_auto_urls # # * => ajouter des options. # => trouver un meilleur nom pour active_link ? (pour le jour ou ca sera tellement une usine # a gaz que on generera des tags :) # # Wiki2xhtml class wiki2xhtmlBasic { var $__version__ = '3.2.2'; var $T; var $opt; var $line; var $acro_table; var $foot_notes; var $macros; var $functions; var $tags; var $open_tags; var $close_tags; var $all_tags; var $tag_pattern; var $escape_table; var $allowed_inline = array(); function wiki2xhtml() { # Mise en place des options $this->setOpt('active_title',1); # Activation des titres !!! $this->setOpt('active_setext_title',0); # Activation des titres setext (EXPERIMENTAL) $this->setOpt('active_hr',1); # Activation des\n"; } elseif ($close && $pre_type == 'list') { $res = ''; for($j = 0; $j < strlen($pre_mode); $j++) { if(substr($pre_mode,(0 - $j - 1), 1) == '*') { $res .= "\n"; } else { $res .= "\n"; } } return $res; } else { return "\n"; } } /* Inline --------------------------------------------------- */ function __inlineWalk($str,$allow_only=NULL) { $tree = preg_split($this->tag_pattern,$str,-1,PREG_SPLIT_DELIM_CAPTURE); $res = ''; for ($i=0; $i
$this->setOpt('active_lists',1); # Activation des listes $this->setOpt('active_quote',1); # Activation du$this->setOpt('active_pre',1); # Activation du\n"; } elseif (($close || $mode != $pre_mode) && $pre_type == 'title') { $fl = $this->getOpt('first_title_level'); $fl = $fl+3; $l = $fl-$pre_mode; return '\n"; } elseif ($close && $pre_type == 'pre') { return "$this->setOpt('active_empty',1); # Activation du bloc vide øøø $this->setOpt('active_auto_urls',0); # Activation de la reconnaissance d'url (inactif) $this->setOpt('active_autoemails',0); # Activation de la reconnaissance des emails (inactif) $this->setOpt('active_antispam',1); # Activation de l'antispam pour les emails $this->setOpt('active_urls',1); # Activation des liens [] $this->setOpt('active_auto_img',1); # Activation des images automatiques dans les liens [] $this->setOpt('active_img',1); # Activation des images (()) $this->setOpt('active_anchor',1); # Activation des ancres ~...~ $this->setOpt('active_em',1); # Activation du ''...'' $this->setOpt('active_strong',1); # Activation du __...__ $this->setOpt('active_br',1); # Activation du
%%% $this->setOpt('active_q',1); # Activation du{{...}} $this->setOpt('active_code',1); # Activation du@@...@@ $this->setOpt('active_acronym',1); # Activation des acronymes $this->setOpt('active_ins',1); # Activation des ins ++..++ $this->setOpt('active_del',1); # Activation des del --..-- $this->setOpt('active_footnotes',1); # Activation des notes de bas de page $this->setOpt('active_wikiwords',0); # Activation des mots wiki $this->setOpt('active_macros',1); # Activation des macros {{{ }}} $this->setOpt('parse_pre',1); # Parser l'intérieur de blocs
? $this->setOpt('active_fix_word_entities',1); # Fixe les caractères MS $this->setOpt('active_fr_syntax',1); # Corrections syntaxe FR $this->setOpt('first_title_level',3); # Premier niveau de titre$this->setOpt('note_prefix','wiki-footnote'); $this->setOpt('note_str',' '); $this->setOpt('words_pattern','((?setOpt('mail_pattern','/^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$/'); $this->setOpt('acronyms_file',dirname(__FILE__).'/acronyms.txt'); $this->acro_table = $this->__getAcronyms(); $this->foot_notes = array(); $this->functions = array(); $this->macros = array(); $this->registerFunction('macro:html',array($this,'__macroHTML')); } function setOpt($option, $value) { $this->opt[$option] = $value; } function getOpt($option) { return (!empty($this->opt[$option])) ? $this->opt[$option] : false; } function registerFunction($type,$name) { if (is_callable($name)) { $this->functions[$type] = $name; } else { trigger_error('Wiki2xhtml : Function does not exist', E_USER_NOTICE); } } function transform($in) { # Initialisation des tags $this->__initTags(); $this->foot_notes = array(); # Récupération des macros if ($this->getOpt('active_macros')) { $in = preg_replace('#^///(.*?)///($|\r)#mse',"\\\$this->__getMacro('\\1')",$in); } # Vérification du niveau de titre if ($this->getOpt('first_title_level') > 4) { $this->setOpt('first_title_level',4); } $res = str_replace("\r", '', $in); $escape_pattern = array(); # traitement des titres à la setext if ($this->getOpt('active_setext_title') && $this->getOpt('active_title')) { $res = preg_replace('/^(.*)\n[=]{5,}$/m','!!!$1',$res); $res = preg_replace('/^(.*)\n[-]{5,}$/m','!!$1',$res); } # Transformation des mots Wiki if ($this->getOpt('active_wikiwords') && $this->getOpt('words_pattern')) { $res = preg_replace('/'.$this->getOpt('words_pattern').'/ms','¶¶¶$1¶¶¶',$res); } $this->T = explode("\n",$res); $this->T[] = ''; # Parse les blocs $res = $this->__parseBlocks(); # Line break if ($this->getOpt('active_br')) { $res = preg_replace('/(?', $res); $escape_pattern[] = '%%%'; } # Correction des caractères faits par certains traitement # de texte comme Word if ($this->getOpt('active_fix_word_entities')) { $wR = array( '‚' => '‚', 'ƒ' => 'ƒ', '„' => '„', '…' => '…', '†' => '†', '‡' => '‡', 'ˆ' => 'ˆ', '‰' => '‰', 'Š' => 'Š', '‹' => '‹', 'Œ' => 'Œ', '‘' => '‘', '’' => '’', '“' => '“', '”' => '”', '•' => '•', '–' => '–', '—' => '—', '˜' => '˜', '™' => '™', 'š' => 'š', '›' => '›', 'œ' => 'œ', 'Ÿ' => 'Ÿ', '€' => '€'); $res = str_replace(array_keys($wR),array_values($wR),$res); } # Nettoyage des \s en trop $res = preg_replace('/([\s]+)(<\/p>|<\/li>|<\/pre>)/', '$2', $res); $res = preg_replace('/(Notes
%s)([\s]+)/', '$1', $res); # On vire les escapes $res = preg_replace('/\\\('.implode('|',$escape_pattern).')/','$1',$res); # On vire les ¶¶¶MotWiki¶¶¶ qui sont resté (dans les url...) if ($this->getOpt('active_wikiwords') && $this->getOpt('words_pattern')) { $res = preg_replace('/¶¶¶'.$this->getOpt('words_pattern').'¶¶¶/msU','$1',$res); } # On remet les macros if ($this->getOpt('active_macros')) { $res = preg_replace('/^##########MACRO#([0-9]+)#$/mse','\$this->__putMacro("$1")',$res); } # On ajoute les notes if (count($this->foot_notes) > 0) { $res_notes = ''; $i = 1; foreach ($this->foot_notes as $k => $v) { $res_notes .= "\n".' \n"; for($j = 0; $j < abs($delta); $j++) { if (substr($pre_mode,(0 - $j - 1), 1) == '*') { $res .= "\n\n"; } else { $res .= "\n\n"; } } } else { $res .= "\n"; } return $res."['.$i.'] '.$v.'
'; $i++; } $res .= sprintf("\n".$this->getOpt('note_str')."\n",$res_notes); } return $res; } /* PRIVATE --------------------------------------------------- */ function __initTags() { $this->tags = array( 'em' => array("''","''"), 'strong' => array('__','__'), 'acronym' => array('??','??'), 'a' => array('[',']'), 'img' => array('((','))'), 'q' => array('{{','}}'), 'code' => array('@@','@@'), 'anchor' => array('~','~'), 'del' => array('--','--'), 'ins' => array('++','++'), 'note' => array('$$','$$'), 'word' => array('¶¶¶','¶¶¶') ); # Suppression des tags selon les options if (!$this->getOpt('active_urls')) { unset($this->tags['a']); } if (!$this->getOpt('active_img')) { unset($this->tags['img']); } if (!$this->getOpt('active_anchor')) { unset($this->tags['anchor']); } if (!$this->getOpt('active_em')) { unset($this->tags['em']); } if (!$this->getOpt('active_strong')) { unset($this->tags['strong']); } if (!$this->getOpt('active_q')) { unset($this->tags['q']); } if (!$this->getOpt('active_code')) { unset($this->tags['code']); } if (!$this->getOpt('active_acronym')) { unset($this->tags['acronym']); } if (!$this->getOpt('active_ins')) { unset($this->tags['ins']); } if (!$this->getOpt('active_del')) { unset($this->tags['del']); } if (!$this->getOpt('active_footnotes')) { unset($this->tags['note']); } if (!$this->getOpt('active_wikiwords')) { unset($this->tags['word']); } $this->open_tags = $this->__getTags(); $this->close_tags = $this->__getTags(false); $this->all_tags = $this->__getAllTags(); $this->tag_pattern = $this->__getTagsPattern(); $this->escape_table = $this->all_tags; array_walk($this->escape_table,create_function('&$a','$a = \'\\\\\'.$a;')); } function __getTags($open=true) { $res = array(); foreach ($this->tags as $k => $v) { $res[$k] = ($open) ? $v[0] : $v[1]; } return $res; } function __getAllTags() { $res = array(); foreach ($this->tags as $v) { $res[] = $v[0]; $res[] = $v[1]; } return array_values(array_unique($res)); } function __getTagsPattern($escape=false) { $res = $this->all_tags; array_walk($res,create_function('&$a','$a = preg_quote($a,"/");')); if (!$escape) { return '/(?T); for ($i=0; $i<$max; $i++) { $pre_mode = $mode; $pre_type = $type; $end = ($i+1 == $max); $line = $this->__getLine($i,$type,$mode); if ($type != 'pre' || $this->getOpt('parse_pre')) { $line = $this->__inlineWalk($line); } $res .= $this->__closeLine($type,$mode,$pre_type,$pre_mode); $res .= $this->__openLine($type,$mode,$pre_type,$pre_mode); # P dans les blockquotes if ($type == 'blockquote' && trim($line) == '' && $pre_type == $type) { $res .= "\n"; } # Correction de la syntaxe FR dans tous sauf pre et hr # Sur idée de Christophe Bonijol # Changement de regex (Nicolas Chachereau) if ($this->getOpt('active_fr_syntax') && $type != NULL && $type != 'pre' && $type != 'hr') { $line = preg_replace('/[ ]+([:?!;](\s|$))/',' $1',$line); $line = preg_replace('/[ ]+(»)/',' $1',$line); $line = preg_replace('/(«)[ ]+/','$1 ',$line); } $res .= $line; } return trim($res); } function __getLine($i,&$type,&$mode) { $pre_type = $type; $pre_mode = $mode; $type = $mode = NULL; if (empty($this->T[$i])) { return false; } $line = htmlspecialchars($this->T[$i],ENT_NOQUOTES); # Ligne vide if (empty($line)) { $type = NULL; } elseif ($this->getOpt('active_empty') && preg_match('/^øøø(.*)$/',$line,$cap)) { $type = NULL; $line = trim($cap[1]); } # Titre elseif ($this->getOpt('active_title') && preg_match('/^([!]{1,4})(.*)$/',$line,$cap)) { $type = 'title'; $mode = strlen($cap[1]); $line = trim($cap[2]); } # Ligne HR elseif ($this->getOpt('active_hr') && preg_match('/^[-]{4}[- ]*$/',$line)) { $type = 'hr'; $line = NULL; } # Blockquote elseif ($this->getOpt('active_quote') && preg_match('/^(>|;:)(.*)$/',$line,$cap)) { $type = 'blockquote'; $line = trim($cap[2]); } # Liste elseif ($this->getOpt('active_lists') && preg_match('/^([*#]+)(.*)$/',$line,$cap)) { $type = 'list'; $mode = $cap[1]; $valid = true; # Vérification d'intégrité $dl = ($type != $pre_type) ? 0 : strlen($pre_mode); $d = strlen($mode); $delta = $d-$dl; if ($delta < 0 && strpos($pre_mode,$mode) !== 0) { $valid = false; } if ($delta > 0 && $type == $pre_type && strpos($mode,$pre_mode) !== 0) { $valid = false; } if ($delta == 0 && $mode != $pre_mode) { $valid = false; } if ($delta > 1) { $valid = false; } if (!$valid) { $type = 'p'; $mode = NULL; $line = '
'.$line; } else { $line = trim($cap[2]); } } # Préformaté elseif ($this->getOpt('active_pre') && preg_match('/^[ ]{1}(.*)$/',$line,$cap)) { $type = 'pre'; $line = $cap[1]; } # Paragraphe else { $type = 'p'; $line = trim($line); } return $line; } function __openLine($type,$mode,$pre_type,$pre_mode) { $open = ($type != $pre_type); if ($open && $type == 'p') { return "\n"; } elseif ($open && $type == 'blockquote') { return "\n
"; } elseif (($open || $mode != $pre_mode) && $type == 'title') { $fl = $this->getOpt('first_title_level'); $fl = $fl+3; $l = $fl-$mode; return "\n
'; } elseif ($open && $type == 'pre') { return "\n "; } elseif ($open && $type == 'hr') { return "\n
"; } elseif ($type == 'list') { $dl = ($open) ? 0 : strlen($pre_mode); $d = strlen($mode); $delta = $d-$dl; $res = ''; if($delta > 0) { if(substr($mode, -1, 1) == '*') { $res .= "\n"; } else { $res .= "
\n"; } } elseif ($delta < 0) { $res .= "
"; } else { return NULL; } } function __closeLine($type,$mode,$pre_type,$pre_mode) { $close = ($type != $pre_type); if ($close && $pre_type == 'p') { return "\n"; } elseif ($close && $pre_type == 'blockquote') { return "
return ''.htmlspecialchars($this->macros[$id]).''; } return null; } function __macroHTML($s) { return $s; } /* Aide et debug --------------------------------------------------- */ function help() { $help['b'] = array(); $help['i'] = array(); $help['b'][] = 'Laisser une ligne vide entre chaque bloc de même nature.'; $help['b'][] = 'Paragraphe : du texte et une ligne vide'; if ($this->getOpt('active_title')) { $help['b'][] = 'Titre :!!!
,!!
, '. '!
pour des titres plus ou moins importants'; } if ($this->getOpt('active_hr')) { $help['b'][] = 'Trait horizontal :----
'; } if ($this->getOpt('active_lists')) { $help['b'][] = 'Liste : ligne débutant par*
ou '. '#
. Il est possible de mélanger les listes '. '(*#*
) pour faire des listes de plusieurs niveaux. '. 'Respecter le style de chaque niveau'; } if ($this->getOpt('active_pre')) { $help['b'][] = 'Texte préformaté : espace devant chaque ligne de texte'; } if ($this->getOpt('active_quote')) { $help['b'][] = 'Bloc de citation :>
ou '. ';:
devant chaque ligne de texte'; } if ($this->getOpt('active_fr_syntax')) { $help['i'][] = 'La correction de ponctuation est active. Un espace '. 'insécable remplacera automatiquement tout espace '. 'précédant les marques ";","?",":" et "!".'; } if ($this->getOpt('active_em')) { $help['i'][] = 'Emphase : deux apostrophes\'\'texte\'\'
'; } if ($this->getOpt('active_strong')) { $help['i'][] = 'Forte emphase : deux soulignés__texte__
'; } if ($this->getOpt('active_br')) { $help['i'][] = 'Retour forcé à la ligne :%%%
'; } if ($this->getOpt('active_ins')) { $help['i'][] = 'Insertion : deux plus++texte++
'; } if ($this->getOpt('active_del')) { $help['i'][] = 'Suppression : deux moins--texte--
'; } if ($this->getOpt('active_urls')) { $help['i'][] = 'Lien :[url]
,[nom|url]
, '. '[nom|url|langue]
ou[nom|url|langue|titre]
.'; $help['i'][] = 'Image : comme un lien mais avec une extension d\'image.'. '
Pour désactiver la reconnaissance d\'image mettez 0 dans un dernier '. 'argument. Par exemple[image|image.gif||0]
fera un lien vers l\'image au '. 'lieu de l\'afficher.'. '
Il est conseillé d\'utiliser la nouvelle syntaxe.'; } if ($this->getOpt('active_img')) { $help['i'][] = 'Image (nouvelle syntaxe) : '. '((url|texte alternatif))
, '. '((url|texte alternatif|position))
ou '. '((url|texte alternatif|position|description longue))
. '. '
La position peut prendre les valeur L ou G (gauche), R ou D (droite) ou C (centré).'; } if ($this->getOpt('active_anchor')) { $help['i'][] = 'Ancre :~ancre~
'; } if ($this->getOpt('active_acronym')) { $help['i'][] = 'Acronyme :??acronyme??
ou '. '??acronyme|titre??
'; } if ($this->getOpt('active_q')) { $help['i'][] = 'Citation :{{citation}}
, '. '{{citation|langue}}
ou{{citation|langue|url}}
'; } if ($this->getOpt('active_code')) { $help['i'][] = 'Code :@@code ici@@
'; } if ($this->getOpt('active_footnotes')) { $help['i'][] = 'Note de bas de page :$$Corps de la note$$
'; } $res = '
p-mode | p-type | mode | type | chaine |
---|---|---|---|---|
'.$pre_mode.' | '.$pre_type.' | '. ''.$mode.' | '.$type.' | '.$line.' |