You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
6.1 KiB
218 lines
6.1 KiB
<?php
|
|
|
|
/**
|
|
* Creole parser implementation
|
|
*
|
|
* @author Josep Arús
|
|
*
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
|
* @package mod_wiki
|
|
*/
|
|
|
|
include_once("wikimarkup.php");
|
|
|
|
class creole_parser extends wiki_markup_parser {
|
|
|
|
protected $blockrules = array(
|
|
'nowiki' => array(
|
|
'expression' => "/^\{\{\{(.*?)\}\}\}/ims",
|
|
'tags' => array(),
|
|
'token' => array('{{{', '}}}')
|
|
),
|
|
'header' => array(
|
|
'expression' => "/^\ *(={1,6})\ *(.+?)=*\ *$/ims",
|
|
'tags' => array(), //none
|
|
'token' => '='
|
|
),
|
|
'table' => array(
|
|
'expression' => "/^(?:\|.*?\|\ *\n)+/ims"
|
|
),
|
|
'line_break' => array(
|
|
'expression' => "/^----\s*$/im",
|
|
'token' => '----',
|
|
'tags' => array()
|
|
),
|
|
'list' => array(
|
|
'expression' => "/((?:^\ *[\*#][^\*#]\ *.+?)(?:^\ *[\*#]{1,5}\ *.+?)*)(\n\s*(?:\n|<(?:h\d|pre|table|tbody|thead|tr|th|td|ul|li|ol|hr)))/ims",
|
|
'tags' => array(),
|
|
'token' => array('*', '#')
|
|
),
|
|
'paragraph' => array(
|
|
'expression' => "/^\ *((?:<(?!\ *\/?(?:h\d|pre|table|tbody|thead|tr|th|td|ul|li|ol|hr)\ *\/?>)|[^<\s]).+?)\n\s*\n/ims",
|
|
//not specified -> all tags (null or unset)
|
|
'tag' => 'p'
|
|
)
|
|
);
|
|
|
|
protected $tagrules = array(
|
|
'nowiki' => array(
|
|
'expression' => "/\{\{\{(.*?)\}\}\}/is",
|
|
'token' => array('{{{', '}}}')
|
|
),
|
|
'image' => array(
|
|
'expression' => "/\~?\{\{(.+)\|(.+)\}\}/i",
|
|
'tags' => array(),
|
|
'token' => array('{{', '|Alt}}')
|
|
),
|
|
'link' => array(
|
|
'expression' => "/\~?\[\[(.+?)\]\]/is",
|
|
'tag' => 'a',
|
|
'token' => array('[[', ']]')
|
|
),
|
|
'url' => array(
|
|
'expression' => "/\~?(?<!=\")((?:https?|ftp):\/\/[^\s\n]+[^,\.\?!:;\"\'\n\ ])/is",
|
|
'tag' => 'a',
|
|
'token' => "http://"
|
|
),
|
|
'line_break' => array(
|
|
'expression' => "/\\\\\\\\/",
|
|
'tag' => 'br',
|
|
'simple' => true,
|
|
'token' => '----'
|
|
),
|
|
'bold' => array(
|
|
'expression' => "/\*\*(.*?)(?:\*\*|$)/is",
|
|
'tag' => 'strong',
|
|
'token' => array('**', '**')
|
|
),
|
|
'italic' => array(
|
|
'expression' => "#(?<!http:|https:|ftp:)//(.+?)(?<!http:|https:|ftp:)//#is",
|
|
'tag' => 'em',
|
|
'token' => array('//', '//')
|
|
)
|
|
);
|
|
|
|
/**
|
|
* Block hooks
|
|
*/
|
|
|
|
protected function before_parsing() {
|
|
$this->string = htmlspecialchars($this->string);
|
|
parent::before_parsing();
|
|
}
|
|
|
|
public function get_section($header, $text, $clean = false) {
|
|
// The requested header is likely to have been passed to htmlspecialchars in
|
|
// self::before_parsing(), therefore we should decode it when looking for it.
|
|
return parent::get_section(htmlspecialchars_decode($header), $text, $clean);
|
|
}
|
|
|
|
protected function header_block_rule($match) {
|
|
$num = strlen($match[1]);
|
|
|
|
$text = trim($match[2]);
|
|
|
|
$text = preg_replace("/\s*={1,$num}$/im", "", $text);
|
|
|
|
return $this->generate_header($text, $num);
|
|
}
|
|
|
|
/**
|
|
* Table generation
|
|
*/
|
|
|
|
protected function table_block_rule($match) {
|
|
|
|
$rows = explode("\n", $match[0]);
|
|
$table = array();
|
|
foreach($rows as $r) {
|
|
if(empty($r)) {
|
|
continue;
|
|
}
|
|
$rawcells = explode("|", $r);
|
|
$cells = array();
|
|
|
|
array_shift($rawcells);
|
|
array_pop($rawcells);
|
|
|
|
foreach($rawcells as $c) {
|
|
if(!empty($c)) {
|
|
if($c[0] == "=") {
|
|
$type = 'header';
|
|
$c = substr($c, 1);
|
|
}
|
|
else {
|
|
$type = 'normal';
|
|
}
|
|
$this->rules($c);
|
|
$cells[] = array($type, $c);
|
|
}
|
|
}
|
|
$table[] = $cells;
|
|
}
|
|
|
|
return $this->generate_table($table);
|
|
}
|
|
|
|
protected function paragraph_block_rule($match) {
|
|
$text = $match[1];
|
|
foreach($this->tagrules as $tr) {
|
|
if(isset($tr['token'])) {
|
|
if(is_array($tr['token'])) {
|
|
$this->escape_token_string($text, $tr['token'][0]);
|
|
$this->escape_token_string($text, $tr['token'][1]);
|
|
}
|
|
else {
|
|
$this->escape_token_string($text, $tr['token']);
|
|
}
|
|
}
|
|
}
|
|
$this->escape_token_string($text, "~");
|
|
|
|
return $text;
|
|
}
|
|
|
|
/**
|
|
* Escape token when it is "negated"
|
|
*/
|
|
private function escape_token_string(&$text, $token) {
|
|
$text = str_replace("~".$token, $this->protect($token), $text);
|
|
}
|
|
|
|
/**
|
|
* Tag functions
|
|
*/
|
|
|
|
protected function url_tag_rule($match) {
|
|
if(strpos($match[0], "~") === 0) {
|
|
return substr($match[0], 1);
|
|
}
|
|
else {
|
|
$text = trim($match[0]);
|
|
$options = array('href' => $text);
|
|
|
|
return array($text, $options);
|
|
}
|
|
}
|
|
|
|
protected function link_tag_rule($match) {
|
|
$text = trim($match[1]);
|
|
|
|
if(strpos($match[0], "~") === 0) {
|
|
return substr($match[0], 1);
|
|
}
|
|
else {
|
|
return $this->format_link($text);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Special treatment of // ** // ** //
|
|
*/
|
|
protected function bold_tag_rule($match) {
|
|
$text = $match[1];
|
|
$this->rules($text, array('only' => array('italic')));
|
|
if(strpos($text, "//") !== false) {
|
|
$text = str_replace("//", $this->protect("//"), $text);
|
|
}
|
|
return array($text, array());
|
|
}
|
|
|
|
protected function image_tag_rule($match) {
|
|
if(strpos($match[0], "~") === 0) {
|
|
return substr($match[0], 1);
|
|
}
|
|
|
|
return $this->format_image($match[1], $match[2]);
|
|
}
|
|
}
|
|
|