diff options
author | ahriman <ahriman@falte.red> | 2019-01-02 04:57:35 +0000 |
---|---|---|
committer | ahriman <ahriman@falte.red> | 2019-01-02 04:57:35 +0000 |
commit | 2bd7f83a6495011ada78ca8a9f2af417caf01760 (patch) | |
tree | f9acdb7f09e011c65330ab993d4db3620787dbfb /wiki/inc/parser | |
parent | bcb215c3a7e914d05f166846a33860e48bba64fb (diff) | |
download | site-2bd7f83a6495011ada78ca8a9f2af417caf01760.tar.gz |
removed dokuwiki
Diffstat (limited to 'wiki/inc/parser')
-rw-r--r-- | wiki/inc/parser/code.php | 73 | ||||
-rw-r--r-- | wiki/inc/parser/handler.php | 1811 | ||||
-rw-r--r-- | wiki/inc/parser/lexer.php | 614 | ||||
-rw-r--r-- | wiki/inc/parser/metadata.php | 694 | ||||
-rw-r--r-- | wiki/inc/parser/parser.php | 1034 | ||||
-rw-r--r-- | wiki/inc/parser/renderer.php | 883 | ||||
-rw-r--r-- | wiki/inc/parser/xhtml.php | 1970 | ||||
-rw-r--r-- | wiki/inc/parser/xhtmlsummary.php | 89 |
8 files changed, 0 insertions, 7168 deletions
diff --git a/wiki/inc/parser/code.php b/wiki/inc/parser/code.php deleted file mode 100644 index f91f1d2..0000000 --- a/wiki/inc/parser/code.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php -/** - * A simple renderer that allows downloading of code and file snippets - * - * @author Andreas Gohr <andi@splitbrain.org> - */ -if(!defined('DOKU_INC')) die('meh.'); - -class Doku_Renderer_code extends Doku_Renderer { - var $_codeblock = 0; - - /** - * Send the wanted code block to the browser - * - * When the correct block was found it exits the script. - * - * @param string $text - * @param string $language - * @param string $filename - */ - function code($text, $language = null, $filename = '') { - global $INPUT; - if(!$language) $language = 'txt'; - $language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language); - if(!$filename) $filename = 'snippet.'.$language; - $filename = utf8_basename($filename); - $filename = utf8_stripspecials($filename, '_'); - - // send CRLF to Windows clients - if(strpos($INPUT->server->str('HTTP_USER_AGENT'), 'Windows') !== false) { - $text = str_replace("\n", "\r\n", $text); - } - - if($this->_codeblock == $INPUT->str('codeblock')) { - header("Content-Type: text/plain; charset=utf-8"); - header("Content-Disposition: attachment; filename=$filename"); - header("X-Robots-Tag: noindex"); - echo trim($text, "\r\n"); - exit; - } - - $this->_codeblock++; - } - - /** - * Wraps around code() - * - * @param string $text - * @param string $language - * @param string $filename - */ - function file($text, $language = null, $filename = '') { - $this->code($text, $language, $filename); - } - - /** - * This should never be reached, if it is send a 404 - */ - function document_end() { - http_status(404); - echo '404 - Not found'; - exit; - } - - /** - * Return the format of the renderer - * - * @returns string 'code' - */ - function getFormat() { - return 'code'; - } -} diff --git a/wiki/inc/parser/handler.php b/wiki/inc/parser/handler.php deleted file mode 100644 index 780c6cf..0000000 --- a/wiki/inc/parser/handler.php +++ /dev/null @@ -1,1811 +0,0 @@ -<?php -if(!defined('DOKU_INC')) die('meh.'); -if (!defined('DOKU_PARSER_EOL')) define('DOKU_PARSER_EOL',"\n"); // add this to make handling test cases simpler - -class Doku_Handler { - - var $Renderer = null; - - var $CallWriter = null; - - var $calls = array(); - - var $status = array( - 'section' => false, - 'doublequote' => 0, - ); - - var $rewriteBlocks = true; - - function __construct() { - $this->CallWriter = new Doku_Handler_CallWriter($this); - } - - /** - * @param string $handler - * @param mixed $args - * @param integer|string $pos - */ - function _addCall($handler, $args, $pos) { - $call = array($handler,$args, $pos); - $this->CallWriter->writeCall($call); - } - - function addPluginCall($plugin, $args, $state, $pos, $match) { - $call = array('plugin',array($plugin, $args, $state, $match), $pos); - $this->CallWriter->writeCall($call); - } - - function _finalize(){ - - $this->CallWriter->finalise(); - - if ( $this->status['section'] ) { - $last_call = end($this->calls); - array_push($this->calls,array('section_close',array(), $last_call[2])); - } - - if ( $this->rewriteBlocks ) { - $B = new Doku_Handler_Block(); - $this->calls = $B->process($this->calls); - } - - trigger_event('PARSER_HANDLER_DONE',$this); - - array_unshift($this->calls,array('document_start',array(),0)); - $last_call = end($this->calls); - array_push($this->calls,array('document_end',array(),$last_call[2])); - } - - /** - * fetch the current call and advance the pointer to the next one - * - * @return bool|mixed - */ - function fetch() { - $call = current($this->calls); - if($call !== false) { - next($this->calls); //advance the pointer - return $call; - } - return false; - } - - - /** - * Special plugin handler - * - * This handler is called for all modes starting with 'plugin_'. - * An additional parameter with the plugin name is passed - * - * @author Andreas Gohr <andi@splitbrain.org> - * - * @param string|integer $match - * @param string|integer $state - * @param integer $pos - * @param $pluginname - * - * @return bool - */ - function plugin($match, $state, $pos, $pluginname){ - $data = array($match); - /** @var DokuWiki_Syntax_Plugin $plugin */ - $plugin = plugin_load('syntax',$pluginname); - if($plugin != null){ - $data = $plugin->handle($match, $state, $pos, $this); - } - if ($data !== false) { - $this->addPluginCall($pluginname,$data,$state,$pos,$match); - } - return true; - } - - function base($match, $state, $pos) { - switch ( $state ) { - case DOKU_LEXER_UNMATCHED: - $this->_addCall('cdata',array($match), $pos); - return true; - break; - } - } - - function header($match, $state, $pos) { - // get level and title - $title = trim($match); - $level = 7 - strspn($title,'='); - if($level < 1) $level = 1; - $title = trim($title,'='); - $title = trim($title); - - if ($this->status['section']) $this->_addCall('section_close',array(),$pos); - - $this->_addCall('header',array($title,$level,$pos), $pos); - - $this->_addCall('section_open',array($level),$pos); - $this->status['section'] = true; - return true; - } - - function notoc($match, $state, $pos) { - $this->_addCall('notoc',array(),$pos); - return true; - } - - function nocache($match, $state, $pos) { - $this->_addCall('nocache',array(),$pos); - return true; - } - - function linebreak($match, $state, $pos) { - $this->_addCall('linebreak',array(),$pos); - return true; - } - - function eol($match, $state, $pos) { - $this->_addCall('eol',array(),$pos); - return true; - } - - function hr($match, $state, $pos) { - $this->_addCall('hr',array(),$pos); - return true; - } - - /** - * @param string|integer $match - * @param string|integer $state - * @param integer $pos - * @param string $name - */ - function _nestingTag($match, $state, $pos, $name) { - switch ( $state ) { - case DOKU_LEXER_ENTER: - $this->_addCall($name.'_open', array(), $pos); - break; - case DOKU_LEXER_EXIT: - $this->_addCall($name.'_close', array(), $pos); - break; - case DOKU_LEXER_UNMATCHED: - $this->_addCall('cdata',array($match), $pos); - break; - } - } - - function strong($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'strong'); - return true; - } - - function emphasis($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'emphasis'); - return true; - } - - function underline($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'underline'); - return true; - } - - function monospace($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'monospace'); - return true; - } - - function subscript($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'subscript'); - return true; - } - - function superscript($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'superscript'); - return true; - } - - function deleted($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'deleted'); - return true; - } - - - function footnote($match, $state, $pos) { -// $this->_nestingTag($match, $state, $pos, 'footnote'); - if (!isset($this->_footnote)) $this->_footnote = false; - - switch ( $state ) { - case DOKU_LEXER_ENTER: - // footnotes can not be nested - however due to limitations in lexer it can't be prevented - // we will still enter a new footnote mode, we just do nothing - if ($this->_footnote) { - $this->_addCall('cdata',array($match), $pos); - break; - } - - $this->_footnote = true; - - $ReWriter = new Doku_Handler_Nest($this->CallWriter,'footnote_close'); - $this->CallWriter = & $ReWriter; - $this->_addCall('footnote_open', array(), $pos); - break; - case DOKU_LEXER_EXIT: - // check whether we have already exitted the footnote mode, can happen if the modes were nested - if (!$this->_footnote) { - $this->_addCall('cdata',array($match), $pos); - break; - } - - $this->_footnote = false; - - $this->_addCall('footnote_close', array(), $pos); - $this->CallWriter->process(); - $ReWriter = & $this->CallWriter; - $this->CallWriter = & $ReWriter->CallWriter; - break; - case DOKU_LEXER_UNMATCHED: - $this->_addCall('cdata', array($match), $pos); - break; - } - return true; - } - - function listblock($match, $state, $pos) { - switch ( $state ) { - case DOKU_LEXER_ENTER: - $ReWriter = new Doku_Handler_List($this->CallWriter); - $this->CallWriter = & $ReWriter; - $this->_addCall('list_open', array($match), $pos); - break; - case DOKU_LEXER_EXIT: - $this->_addCall('list_close', array(), $pos); - $this->CallWriter->process(); - $ReWriter = & $this->CallWriter; - $this->CallWriter = & $ReWriter->CallWriter; - break; - case DOKU_LEXER_MATCHED: - $this->_addCall('list_item', array($match), $pos); - break; - case DOKU_LEXER_UNMATCHED: - $this->_addCall('cdata', array($match), $pos); - break; - } - return true; - } - - function unformatted($match, $state, $pos) { - if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('unformatted',array($match), $pos); - } - return true; - } - - function php($match, $state, $pos) { - global $conf; - if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('php',array($match), $pos); - } - return true; - } - - function phpblock($match, $state, $pos) { - global $conf; - if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('phpblock',array($match), $pos); - } - return true; - } - - function html($match, $state, $pos) { - global $conf; - if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('html',array($match), $pos); - } - return true; - } - - function htmlblock($match, $state, $pos) { - global $conf; - if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('htmlblock',array($match), $pos); - } - return true; - } - - function preformatted($match, $state, $pos) { - switch ( $state ) { - case DOKU_LEXER_ENTER: - $ReWriter = new Doku_Handler_Preformatted($this->CallWriter); - $this->CallWriter = $ReWriter; - $this->_addCall('preformatted_start',array(), $pos); - break; - case DOKU_LEXER_EXIT: - $this->_addCall('preformatted_end',array(), $pos); - $this->CallWriter->process(); - $ReWriter = & $this->CallWriter; - $this->CallWriter = & $ReWriter->CallWriter; - break; - case DOKU_LEXER_MATCHED: - $this->_addCall('preformatted_newline',array(), $pos); - break; - case DOKU_LEXER_UNMATCHED: - $this->_addCall('preformatted_content',array($match), $pos); - break; - } - - return true; - } - - function quote($match, $state, $pos) { - - switch ( $state ) { - - case DOKU_LEXER_ENTER: - $ReWriter = new Doku_Handler_Quote($this->CallWriter); - $this->CallWriter = & $ReWriter; - $this->_addCall('quote_start',array($match), $pos); - break; - - case DOKU_LEXER_EXIT: - $this->_addCall('quote_end',array(), $pos); - $this->CallWriter->process(); - $ReWriter = & $this->CallWriter; - $this->CallWriter = & $ReWriter->CallWriter; - break; - - case DOKU_LEXER_MATCHED: - $this->_addCall('quote_newline',array($match), $pos); - break; - - case DOKU_LEXER_UNMATCHED: - $this->_addCall('cdata',array($match), $pos); - break; - - } - - return true; - } - - /** - * Internal function for parsing highlight options. - * $options is parsed for key value pairs separated by commas. - * A value might also be missing in which case the value will simple - * be set to true. Commas in strings are ignored, e.g. option="4,56" - * will work as expected and will only create one entry. - * - * @param string $options space separated list of key-value pairs, - * e.g. option1=123, option2="456" - * @return array|null Array of key-value pairs $array['key'] = 'value'; - * or null if no entries found - */ - protected function parse_highlight_options ($options) { - $result = array(); - preg_match_all('/(\w+(?:="[^"]*"))|(\w+(?:=[^\s]*))|(\w+[^=\s\]])(?:\s*)/', $options, $matches, PREG_SET_ORDER); - foreach ($matches as $match) { - $equal_sign = strpos($match [0], '='); - if ($equal_sign === false) { - $key = trim($match[0]); - $result [$key] = 1; - } else { - $key = substr($match[0], 0, $equal_sign); - $value = substr($match[0], $equal_sign+1); - $value = trim($value, '"'); - if (strlen($value) > 0) { - $result [$key] = $value; - } else { - $result [$key] = 1; - } - } - } - - // Check for supported options - $result = array_intersect_key( - $result, - array_flip(array( - 'enable_line_numbers', - 'start_line_numbers_at', - 'highlight_lines_extra', - 'enable_keyword_links') - ) - ); - - // Sanitize values - if(isset($result['enable_line_numbers'])) { - if($result['enable_line_numbers'] === 'false') { - $result['enable_line_numbers'] = false; - } - $result['enable_line_numbers'] = (bool) $result['enable_line_numbers']; - } - if(isset($result['highlight_lines_extra'])) { - $result['highlight_lines_extra'] = array_map('intval', explode(',', $result['highlight_lines_extra'])); - $result['highlight_lines_extra'] = array_filter($result['highlight_lines_extra']); - $result['highlight_lines_extra'] = array_unique($result['highlight_lines_extra']); - } - if(isset($result['start_line_numbers_at'])) { - $result['start_line_numbers_at'] = (int) $result['start_line_numbers_at']; - } - if(isset($result['enable_keyword_links'])) { - if($result['enable_keyword_links'] === 'false') { - $result['enable_keyword_links'] = false; - } - $result['enable_keyword_links'] = (bool) $result['enable_keyword_links']; - } - if (count($result) == 0) { - return null; - } - - return $result; - } - - function file($match, $state, $pos) { - return $this->code($match, $state, $pos, 'file'); - } - - function code($match, $state, $pos, $type='code') { - if ( $state == DOKU_LEXER_UNMATCHED ) { - $matches = explode('>',$match,2); - // Cut out variable options enclosed in [] - preg_match('/\[.*\]/', $matches[0], $options); - if (!empty($options[0])) { - $matches[0] = str_replace($options[0], '', $matches[0]); - } - $param = preg_split('/\s+/', $matches[0], 2, PREG_SPLIT_NO_EMPTY); - while(count($param) < 2) array_push($param, null); - // We shortcut html here. - if ($param[0] == 'html') $param[0] = 'html4strict'; - if ($param[0] == '-') $param[0] = null; - array_unshift($param, $matches[1]); - if (!empty($options[0])) { - $param [] = $this->parse_highlight_options ($options[0]); - } - $this->_addCall($type, $param, $pos); - } - return true; - } - - function acronym($match, $state, $pos) { - $this->_addCall('acronym',array($match), $pos); - return true; - } - - function smiley($match, $state, $pos) { - $this->_addCall('smiley',array($match), $pos); - return true; - } - - function wordblock($match, $state, $pos) { - $this->_addCall('wordblock',array($match), $pos); - return true; - } - - function entity($match, $state, $pos) { - $this->_addCall('entity',array($match), $pos); - return true; - } - - function multiplyentity($match, $state, $pos) { - preg_match_all('/\d+/',$match,$matches); - $this->_addCall('multiplyentity',array($matches[0][0],$matches[0][1]), $pos); - return true; - } - - function singlequoteopening($match, $state, $pos) { - $this->_addCall('singlequoteopening',array(), $pos); - return true; - } - - function singlequoteclosing($match, $state, $pos) { - $this->_addCall('singlequoteclosing',array(), $pos); - return true; - } - - function apostrophe($match, $state, $pos) { - $this->_addCall('apostrophe',array(), $pos); - return true; - } - - function doublequoteopening($match, $state, $pos) { - $this->_addCall('doublequoteopening',array(), $pos); - $this->status['doublequote']++; - return true; - } - - function doublequoteclosing($match, $state, $pos) { - if ($this->status['doublequote'] <= 0) { - $this->doublequoteopening($match, $state, $pos); - } else { - $this->_addCall('doublequoteclosing',array(), $pos); - $this->status['doublequote'] = max(0, --$this->status['doublequote']); - } - return true; - } - - function camelcaselink($match, $state, $pos) { - $this->_addCall('camelcaselink',array($match), $pos); - return true; - } - - /* - */ - function internallink($match, $state, $pos) { - // Strip the opening and closing markup - $link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match); - - // Split title from URL - $link = explode('|',$link,2); - if ( !isset($link[1]) ) { - $link[1] = null; - } else if ( preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) { - // If the title is an image, convert it to an array containing the image details - $link[1] = Doku_Handler_Parse_Media($link[1]); - } - $link[0] = trim($link[0]); - - //decide which kind of link it is - - if ( link_isinterwiki($link[0]) ) { - // Interwiki - $interwiki = explode('>',$link[0],2); - $this->_addCall( - 'interwikilink', - array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]), - $pos - ); - }elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) { - // Windows Share - $this->_addCall( - 'windowssharelink', - array($link[0],$link[1]), - $pos - ); - }elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) { - // external link (accepts all protocols) - $this->_addCall( - 'externallink', - array($link[0],$link[1]), - $pos - ); - }elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) { - // E-Mail (pattern above is defined in inc/mail.php) - $this->_addCall( - 'emaillink', - array($link[0],$link[1]), - $pos - ); - }elseif ( preg_match('!^#.+!',$link[0]) ){ - // local link - $this->_addCall( - 'locallink', - array(substr($link[0],1),$link[1]), - $pos - ); - }else{ - // internal link - $this->_addCall( - 'internallink', - array($link[0],$link[1]), - $pos - ); - } - - return true; - } - - function filelink($match, $state, $pos) { - $this->_addCall('filelink',array($match, null), $pos); - return true; - } - - function windowssharelink($match, $state, $pos) { - $this->_addCall('windowssharelink',array($match, null), $pos); - return true; - } - - function media($match, $state, $pos) { - $p = Doku_Handler_Parse_Media($match); - - $this->_addCall( - $p['type'], - array($p['src'], $p['title'], $p['align'], $p['width'], - $p['height'], $p['cache'], $p['linking']), - $pos - ); - return true; - } - - function rss($match, $state, $pos) { - $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match); - - // get params - list($link,$params) = explode(' ',$link,2); - - $p = array(); - if(preg_match('/\b(\d+)\b/',$params,$match)){ - $p['max'] = $match[1]; - }else{ - $p['max'] = 8; - } - $p['reverse'] = (preg_match('/rev/',$params)); - $p['author'] = (preg_match('/\b(by|author)/',$params)); - $p['date'] = (preg_match('/\b(date)/',$params)); - $p['details'] = (preg_match('/\b(desc|detail)/',$params)); - $p['nosort'] = (preg_match('/\b(nosort)\b/',$params)); - - if (preg_match('/\b(\d+)([dhm])\b/',$params,$match)) { - $period = array('d' => 86400, 'h' => 3600, 'm' => 60); - $p['refresh'] = max(600,$match[1]*$period[$match[2]]); // n * period in seconds, minimum 10 minutes - } else { - $p['refresh'] = 14400; // default to 4 hours - } - - $this->_addCall('rss',array($link,$p),$pos); - return true; - } - - function externallink($match, $state, $pos) { - $url = $match; - $title = null; - - // add protocol on simple short URLs - if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')){ - $title = $url; - $url = 'ftp://'.$url; - } - if(substr($url,0,3) == 'www' && (substr($url,0,7) != 'http://')){ - $title = $url; - $url = 'http://'.$url; - } - - $this->_addCall('externallink',array($url, $title), $pos); - return true; - } - - function emaillink($match, $state, $pos) { - $email = preg_replace(array('/^</','/>$/'),'',$match); - $this->_addCall('emaillink',array($email, null), $pos); - return true; - } - - function table($match, $state, $pos) { - switch ( $state ) { - - case DOKU_LEXER_ENTER: - - $ReWriter = new Doku_Handler_Table($this->CallWriter); - $this->CallWriter = & $ReWriter; - - $this->_addCall('table_start', array($pos + 1), $pos); - if ( trim($match) == '^' ) { - $this->_addCall('tableheader', array(), $pos); - } else { - $this->_addCall('tablecell', array(), $pos); - } - break; - - case DOKU_LEXER_EXIT: - $this->_addCall('table_end', array($pos), $pos); - $this->CallWriter->process(); - $ReWriter = & $this->CallWriter; - $this->CallWriter = & $ReWriter->CallWriter; - break; - - case DOKU_LEXER_UNMATCHED: - if ( trim($match) != '' ) { - $this->_addCall('cdata',array($match), $pos); - } - break; - - case DOKU_LEXER_MATCHED: - if ( $match == ' ' ){ - $this->_addCall('cdata', array($match), $pos); - } else if ( preg_match('/:::/',$match) ) { - $this->_addCall('rowspan', array($match), $pos); - } else if ( preg_match('/\t+/',$match) ) { - $this->_addCall('table_align', array($match), $pos); - } else if ( preg_match('/ {2,}/',$match) ) { - $this->_addCall('table_align', array($match), $pos); - } else if ( $match == "\n|" ) { - $this->_addCall('table_row', array(), $pos); - $this->_addCall('tablecell', array(), $pos); - } else if ( $match == "\n^" ) { - $this->_addCall('table_row', array(), $pos); - $this->_addCall('tableheader', array(), $pos); - } else if ( $match == '|' ) { - $this->_addCall('tablecell', array(), $pos); - } else if ( $match == '^' ) { - $this->_addCall('tableheader', array(), $pos); - } - break; - } - return true; - } -} - -//------------------------------------------------------------------------ -function Doku_Handler_Parse_Media($match) { - - // Strip the opening and closing markup - $link = preg_replace(array('/^\{\{/','/\}\}$/u'),'',$match); - - // Split title from URL - $link = explode('|',$link,2); - - // Check alignment - $ralign = (bool)preg_match('/^ /',$link[0]); - $lalign = (bool)preg_match('/ $/',$link[0]); - - // Logic = what's that ;)... - if ( $lalign & $ralign ) { - $align = 'center'; - } else if ( $ralign ) { - $align = 'right'; - } else if ( $lalign ) { - $align = 'left'; - } else { - $align = null; - } - - // The title... - if ( !isset($link[1]) ) { - $link[1] = null; - } - - //remove aligning spaces - $link[0] = trim($link[0]); - - //split into src and parameters (using the very last questionmark) - $pos = strrpos($link[0], '?'); - if($pos !== false){ - $src = substr($link[0],0,$pos); - $param = substr($link[0],$pos+1); - }else{ - $src = $link[0]; - $param = ''; - } - - //parse width and height - if(preg_match('#(\d+)(x(\d+))?#i',$param,$size)){ - !empty($size[1]) ? $w = $size[1] : $w = null; - !empty($size[3]) ? $h = $size[3] : $h = null; - } else { - $w = null; - $h = null; - } - - //get linking command - if(preg_match('/nolink/i',$param)){ - $linking = 'nolink'; - }else if(preg_match('/direct/i',$param)){ - $linking = 'direct'; - }else if(preg_match('/linkonly/i',$param)){ - $linking = 'linkonly'; - }else{ - $linking = 'details'; - } - - //get caching command - if (preg_match('/(nocache|recache)/i',$param,$cachemode)){ - $cache = $cachemode[1]; - }else{ - $cache = 'cache'; - } - - // Check whether this is a local or remote image or interwiki - if (media_isexternal($src) || link_isinterwiki($src)){ - $call = 'externalmedia'; - } else { - $call = 'internalmedia'; - } - - $params = array( - 'type'=>$call, - 'src'=>$src, - 'title'=>$link[1], - 'align'=>$align, - 'width'=>$w, - 'height'=>$h, - 'cache'=>$cache, - 'linking'=>$linking, - ); - - return $params; -} - -//------------------------------------------------------------------------ -interface Doku_Handler_CallWriter_Interface { - public function writeCall($call); - public function writeCalls($calls); - public function finalise(); -} - -class Doku_Handler_CallWriter implements Doku_Handler_CallWriter_Interface { - - var $Handler; - - /** - * @param Doku_Handler $Handler - */ - function __construct(Doku_Handler $Handler) { - $this->Handler = $Handler; - } - - function writeCall($call) { - $this->Handler->calls[] = $call; - } - - function writeCalls($calls) { - $this->Handler->calls = array_merge($this->Handler->calls, $calls); - } - - // function is required, but since this call writer is first/highest in - // the chain it is not required to do anything - function finalise() { - unset($this->Handler); - } -} - -//------------------------------------------------------------------------ -/** - * Generic call writer class to handle nesting of rendering instructions - * within a render instruction. Also see nest() method of renderer base class - * - * @author Chris Smith <chris@jalakai.co.uk> - */ -class Doku_Handler_Nest implements Doku_Handler_CallWriter_Interface { - - var $CallWriter; - var $calls = array(); - - var $closingInstruction; - - /** - * constructor - * - * @param Doku_Handler_CallWriter $CallWriter the renderers current call writer - * @param string $close closing instruction name, this is required to properly terminate the - * syntax mode if the document ends without a closing pattern - */ - function __construct(Doku_Handler_CallWriter_Interface $CallWriter, $close="nest_close") { - $this->CallWriter = $CallWriter; - - $this->closingInstruction = $close; - } - - function writeCall($call) { - $this->calls[] = $call; - } - - function writeCalls($calls) { - $this->calls = array_merge($this->calls, $calls); - } - - function finalise() { - $last_call = end($this->calls); - $this->writeCall(array($this->closingInstruction,array(), $last_call[2])); - - $this->process(); - $this->CallWriter->finalise(); - unset($this->CallWriter); - } - - function process() { - // merge consecutive cdata - $unmerged_calls = $this->calls; - $this->calls = array(); - - foreach ($unmerged_calls as $call) $this->addCall($call); - - $first_call = reset($this->calls); - $this->CallWriter->writeCall(array("nest", array($this->calls), $first_call[2])); - } - - function addCall($call) { - $key = count($this->calls); - if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) { - $this->calls[$key-1][1][0] .= $call[1][0]; - } else if ($call[0] == 'eol') { - // do nothing (eol shouldn't be allowed, to counter preformatted fix in #1652 & #1699) - } else { - $this->calls[] = $call; - } - } -} - -class Doku_Handler_List implements Doku_Handler_CallWriter_Interface { - - var $CallWriter; - - var $calls = array(); - var $listCalls = array(); - var $listStack = array(); - - const NODE = 1; - - function __construct(Doku_Handler_CallWriter_Interface $CallWriter) { - $this->CallWriter = $CallWriter; - } - - function writeCall($call) { - $this->calls[] = $call; - } - - // Probably not needed but just in case... - function writeCalls($calls) { - $this->calls = array_merge($this->calls, $calls); -# $this->CallWriter->writeCalls($this->calls); - } - - function finalise() { - $last_call = end($this->calls); - $this->writeCall(array('list_close',array(), $last_call[2])); - - $this->process(); - $this->CallWriter->finalise(); - unset($this->CallWriter); - } - - //------------------------------------------------------------------------ - function process() { - - foreach ( $this->calls as $call ) { - switch ($call[0]) { - case 'list_item': - $this->listOpen($call); - break; - case 'list_open': - $this->listStart($call); - break; - case 'list_close': - $this->listEnd($call); - break; - default: - $this->listContent($call); - break; - } - } - - $this->CallWriter->writeCalls($this->listCalls); - } - - //------------------------------------------------------------------------ - function listStart($call) { - $depth = $this->interpretSyntax($call[1][0], $listType); - - $this->initialDepth = $depth; - // array(list type, current depth, index of current listitem_open) - $this->listStack[] = array($listType, $depth, 1); - - $this->listCalls[] = array('list'.$listType.'_open',array(),$call[2]); - $this->listCalls[] = array('listitem_open',array(1),$call[2]); - $this->listCalls[] = array('listcontent_open',array(),$call[2]); - } - - //------------------------------------------------------------------------ - function listEnd($call) { - $closeContent = true; - - while ( $list = array_pop($this->listStack) ) { - if ( $closeContent ) { - $this->listCalls[] = array('listcontent_close',array(),$call[2]); - $closeContent = false; - } - $this->listCalls[] = array('listitem_close',array(),$call[2]); - $this->listCalls[] = array('list'.$list[0].'_close', array(), $call[2]); - } - } - - //------------------------------------------------------------------------ - function listOpen($call) { - $depth = $this->interpretSyntax($call[1][0], $listType); - $end = end($this->listStack); - $key = key($this->listStack); - - // Not allowed to be shallower than initialDepth - if ( $depth < $this->initialDepth ) { - $depth = $this->initialDepth; - } - - //------------------------------------------------------------------------ - if ( $depth == $end[1] ) { - - // Just another item in the list... - if ( $listType == $end[0] ) { - $this->listCalls[] = array('listcontent_close',array(),$call[2]); - $this->listCalls[] = array('listitem_close',array(),$call[2]); - $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]); - $this->listCalls[] = array('listcontent_open',array(),$call[2]); - - // new list item, update list stack's index into current listitem_open - $this->listStack[$key][2] = count($this->listCalls) - 2; - - // Switched list type... - } else { - - $this->listCalls[] = array('listcontent_close',array(),$call[2]); - $this->listCalls[] = array('listitem_close',array(),$call[2]); - $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]); - $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]); - $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]); - $this->listCalls[] = array('listcontent_open',array(),$call[2]); - - array_pop($this->listStack); - $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2); - } - - //------------------------------------------------------------------------ - // Getting deeper... - } else if ( $depth > $end[1] ) { - - $this->listCalls[] = array('listcontent_close',array(),$call[2]); - $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]); - $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]); - $this->listCalls[] = array('listcontent_open',array(),$call[2]); - - // set the node/leaf state of this item's parent listitem_open to NODE - $this->listCalls[$this->listStack[$key][2]][1][1] = self::NODE; - - $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2); - - //------------------------------------------------------------------------ - // Getting shallower ( $depth < $end[1] ) - } else { - $this->listCalls[] = array('listcontent_close',array(),$call[2]); - $this->listCalls[] = array('listitem_close',array(),$call[2]); - $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]); - - // Throw away the end - done - array_pop($this->listStack); - - while (1) { - $end = end($this->listStack); - $key = key($this->listStack); - - if ( $end[1] <= $depth ) { - - // Normalize depths - $depth = $end[1]; - - $this->listCalls[] = array('listitem_close',array(),$call[2]); - - if ( $end[0] == $listType ) { - $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]); - $this->listCalls[] = array('listcontent_open',array(),$call[2]); - - // new list item, update list stack's index into current listitem_open - $this->listStack[$key][2] = count($this->listCalls) - 2; - - } else { - // Switching list type... - $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]); - $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]); - $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]); - $this->listCalls[] = array('listcontent_open',array(),$call[2]); - - array_pop($this->listStack); - $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2); - } - - break; - - // Haven't dropped down far enough yet.... ( $end[1] > $depth ) - } else { - - $this->listCalls[] = array('listitem_close',array(),$call[2]); - $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]); - - array_pop($this->listStack); - - } - - } - - } - } - - //------------------------------------------------------------------------ - function listContent($call) { - $this->listCalls[] = $call; - } - - //------------------------------------------------------------------------ - function interpretSyntax($match, & $type) { - if ( substr($match,-1) == '*' ) { - $type = 'u'; - } else { - $type = 'o'; - } - // Is the +1 needed? It used to be count(explode(...)) - // but I don't think the number is seen outside this handler - return substr_count(str_replace("\t",' ',$match), ' ') + 1; - } -} - -//------------------------------------------------------------------------ -class Doku_Handler_Preformatted implements Doku_Handler_CallWriter_Interface { - - var $CallWriter; - - var $calls = array(); - var $pos; - var $text =''; - - - - function __construct(Doku_Handler_CallWriter_Interface $CallWriter) { - $this->CallWriter = $CallWriter; - } - - function writeCall($call) { - $this->calls[] = $call; - } - - // Probably not needed but just in case... - function writeCalls($calls) { - $this->calls = array_merge($this->calls, $calls); -# $this->CallWriter->writeCalls($this->calls); - } - - function finalise() { - $last_call = end($this->calls); - $this->writeCall(array('preformatted_end',array(), $last_call[2])); - - $this->process(); - $this->CallWriter->finalise(); - unset($this->CallWriter); - } - - function process() { - foreach ( $this->calls as $call ) { - switch ($call[0]) { - case 'preformatted_start': - $this->pos = $call[2]; - break; - case 'preformatted_newline': - $this->text .= "\n"; - break; - case 'preformatted_content': - $this->text .= $call[1][0]; - break; - case 'preformatted_end': - if (trim($this->text)) { - $this->CallWriter->writeCall(array('preformatted',array($this->text),$this->pos)); - } - // see FS#1699 & FS#1652, add 'eol' instructions to ensure proper triggering of following p_open - $this->CallWriter->writeCall(array('eol',array(),$this->pos)); - $this->CallWriter->writeCall(array('eol',array(),$this->pos)); - break; - } - } - } - -} - -//------------------------------------------------------------------------ -class Doku_Handler_Quote implements Doku_Handler_CallWriter_Interface { - - var $CallWriter; - - var $calls = array(); - - var $quoteCalls = array(); - - function __construct(Doku_Handler_CallWriter_Interface $CallWriter) { - $this->CallWriter = $CallWriter; - } - - function writeCall($call) { - $this->calls[] = $call; - } - - // Probably not needed but just in case... - function writeCalls($calls) { - $this->calls = array_merge($this->calls, $calls); - } - - function finalise() { - $last_call = end($this->calls); - $this->writeCall(array('quote_end',array(), $last_call[2])); - - $this->process(); - $this->CallWriter->finalise(); - unset($this->CallWriter); - } - - function process() { - - $quoteDepth = 1; - - foreach ( $this->calls as $call ) { - switch ($call[0]) { - - case 'quote_start': - - $this->quoteCalls[] = array('quote_open',array(),$call[2]); - - case 'quote_newline': - - $quoteLength = $this->getDepth($call[1][0]); - - if ( $quoteLength > $quoteDepth ) { - $quoteDiff = $quoteLength - $quoteDepth; - for ( $i = 1; $i <= $quoteDiff; $i++ ) { - $this->quoteCalls[] = array('quote_open',array(),$call[2]); - } - } else if ( $quoteLength < $quoteDepth ) { - $quoteDiff = $quoteDepth - $quoteLength; - for ( $i = 1; $i <= $quoteDiff; $i++ ) { - $this->quoteCalls[] = array('quote_close',array(),$call[2]); - } - } else { - if ($call[0] != 'quote_start') $this->quoteCalls[] = array('linebreak',array(),$call[2]); - } - - $quoteDepth = $quoteLength; - - break; - - case 'quote_end': - - if ( $quoteDepth > 1 ) { - $quoteDiff = $quoteDepth - 1; - for ( $i = 1; $i <= $quoteDiff; $i++ ) { - $this->quoteCalls[] = array('quote_close',array(),$call[2]); - } - } - - $this->quoteCalls[] = array('quote_close',array(),$call[2]); - - $this->CallWriter->writeCalls($this->quoteCalls); - break; - - default: - $this->quoteCalls[] = $call; - break; - } - } - } - - function getDepth($marker) { - preg_match('/>{1,}/', $marker, $matches); - $quoteLength = strlen($matches[0]); - return $quoteLength; - } -} - -//------------------------------------------------------------------------ -class Doku_Handler_Table implements Doku_Handler_CallWriter_Interface { - - var $CallWriter; - - var $calls = array(); - var $tableCalls = array(); - var $maxCols = 0; - var $maxRows = 1; - var $currentCols = 0; - var $firstCell = false; - var $lastCellType = 'tablecell'; - var $inTableHead = true; - var $currentRow = array('tableheader' => 0, 'tablecell' => 0); - var $countTableHeadRows = 0; - - function __construct(Doku_Handler_CallWriter_Interface $CallWriter) { - $this->CallWriter = $CallWriter; - } - - function writeCall($call) { - $this->calls[] = $call; - } - - // Probably not needed but just in case... - function writeCalls($calls) { - $this->calls = array_merge($this->calls, $calls); - } - - function finalise() { - $last_call = end($this->calls); - $this->writeCall(array('table_end',array(), $last_call[2])); - - $this->process(); - $this->CallWriter->finalise(); - unset($this->CallWriter); - } - - //------------------------------------------------------------------------ - function process() { - foreach ( $this->calls as $call ) { - switch ( $call[0] ) { - case 'table_start': - $this->tableStart($call); - break; - case 'table_row': - $this->tableRowClose($call); - $this->tableRowOpen(array('tablerow_open',$call[1],$call[2])); - break; - case 'tableheader': - case 'tablecell': - $this->tableCell($call); - break; - case 'table_end': - $this->tableRowClose($call); - $this->tableEnd($call); - break; - default: - $this->tableDefault($call); - break; - } - } - $this->CallWriter->writeCalls($this->tableCalls); - } - - function tableStart($call) { - $this->tableCalls[] = array('table_open',$call[1],$call[2]); - $this->tableCalls[] = array('tablerow_open',array(),$call[2]); - $this->firstCell = true; - } - - function tableEnd($call) { - $this->tableCalls[] = array('table_close',$call[1],$call[2]); - $this->finalizeTable(); - } - - function tableRowOpen($call) { - $this->tableCalls[] = $call; - $this->currentCols = 0; - $this->firstCell = true; - $this->lastCellType = 'tablecell'; - $this->maxRows++; - if ($this->inTableHead) { - $this->currentRow = array('tablecell' => 0, 'tableheader' => 0); - } - } - - function tableRowClose($call) { - if ($this->inTableHead && ($this->inTableHead = $this->isTableHeadRow())) { - $this->countTableHeadRows++; - } - // Strip off final cell opening and anything after it - while ( $discard = array_pop($this->tableCalls ) ) { - - if ( $discard[0] == 'tablecell_open' || $discard[0] == 'tableheader_open') { - break; - } - if (!empty($this->currentRow[$discard[0]])) { - $this->currentRow[$discard[0]]--; - } - } - $this->tableCalls[] = array('tablerow_close', array(), $call[2]); - - if ( $this->currentCols > $this->maxCols ) { - $this->maxCols = $this->currentCols; - } - } - - function isTableHeadRow() { - $td = $this->currentRow['tablecell']; - $th = $this->currentRow['tableheader']; - - if (!$th || $td > 2) return false; - if (2*$td > $th) return false; - - return true; - } - - function tableCell($call) { - if ($this->inTableHead) { - $this->currentRow[$call[0]]++; - } - if ( !$this->firstCell ) { - - // Increase the span - $lastCall = end($this->tableCalls); - - // A cell call which follows an open cell means an empty cell so span - if ( $lastCall[0] == 'tablecell_open' || $lastCall[0] == 'tableheader_open' ) { - $this->tableCalls[] = array('colspan',array(),$call[2]); - - } - - $this->tableCalls[] = array($this->lastCellType.'_close',array(),$call[2]); - $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]); - $this->lastCellType = $call[0]; - - } else { - - $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]); - $this->lastCellType = $call[0]; - $this->firstCell = false; - - } - - $this->currentCols++; - } - - function tableDefault($call) { - $this->tableCalls[] = $call; - } - - function finalizeTable() { - - // Add the max cols and rows to the table opening - if ( $this->tableCalls[0][0] == 'table_open' ) { - // Adjust to num cols not num col delimeters - $this->tableCalls[0][1][] = $this->maxCols - 1; - $this->tableCalls[0][1][] = $this->maxRows; - $this->tableCalls[0][1][] = array_shift($this->tableCalls[0][1]); - } else { - trigger_error('First element in table call list is not table_open'); - } - - $lastRow = 0; - $lastCell = 0; - $cellKey = array(); - $toDelete = array(); - - // if still in tableheader, then there can be no table header - // as all rows can't be within <THEAD> - if ($this->inTableHead) { - $this->inTableHead = false; - $this->countTableHeadRows = 0; - } - - // Look for the colspan elements and increment the colspan on the - // previous non-empty opening cell. Once done, delete all the cells - // that contain colspans - for ($key = 0 ; $key < count($this->tableCalls) ; ++$key) { - $call = $this->tableCalls[$key]; - - switch ($call[0]) { - case 'table_open' : - if($this->countTableHeadRows) { - array_splice($this->tableCalls, $key+1, 0, array( - array('tablethead_open', array(), $call[2])) - ); - } - break; - - case 'tablerow_open': - - $lastRow++; - $lastCell = 0; - break; - - case 'tablecell_open': - case 'tableheader_open': - - $lastCell++; - $cellKey[$lastRow][$lastCell] = $key; - break; - - case 'table_align': - - $prev = in_array($this->tableCalls[$key-1][0], array('tablecell_open', 'tableheader_open')); - $next = in_array($this->tableCalls[$key+1][0], array('tablecell_close', 'tableheader_close')); - // If the cell is empty, align left - if ($prev && $next) { - $this->tableCalls[$key-1][1][1] = 'left'; - - // If the previous element was a cell open, align right - } elseif ($prev) { - $this->tableCalls[$key-1][1][1] = 'right'; - - // If the next element is the close of an element, align either center or left - } elseif ( $next) { - if ( $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] == 'right' ) { - $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'center'; - } else { - $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'left'; - } - - } - - // Now convert the whitespace back to cdata - $this->tableCalls[$key][0] = 'cdata'; - break; - - case 'colspan': - - $this->tableCalls[$key-1][1][0] = false; - - for($i = $key-2; $i >= $cellKey[$lastRow][1]; $i--) { - - if ( $this->tableCalls[$i][0] == 'tablecell_open' || $this->tableCalls[$i][0] == 'tableheader_open' ) { - - if ( false !== $this->tableCalls[$i][1][0] ) { - $this->tableCalls[$i][1][0]++; - break; - } - - } - } - - $toDelete[] = $key-1; - $toDelete[] = $key; - $toDelete[] = $key+1; - break; - - case 'rowspan': - - if ( $this->tableCalls[$key-1][0] == 'cdata' ) { - // ignore rowspan if previous call was cdata (text mixed with :::) we don't have to check next call as that wont match regex - $this->tableCalls[$key][0] = 'cdata'; - - } else { - - $spanning_cell = null; - - // can't cross thead/tbody boundary - if (!$this->countTableHeadRows || ($lastRow-1 != $this->countTableHeadRows)) { - for($i = $lastRow-1; $i > 0; $i--) { - - if ( $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tablecell_open' || $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tableheader_open' ) { - - if ($this->tableCalls[$cellKey[$i][$lastCell]][1][2] >= $lastRow - $i) { - $spanning_cell = $i; - break; - } - - } - } - } - if (is_null($spanning_cell)) { - // No spanning cell found, so convert this cell to - // an empty one to avoid broken tables - $this->tableCalls[$key][0] = 'cdata'; - $this->tableCalls[$key][1][0] = ''; - continue; - } - $this->tableCalls[$cellKey[$spanning_cell][$lastCell]][1][2]++; - - $this->tableCalls[$key-1][1][2] = false; - - $toDelete[] = $key-1; - $toDelete[] = $key; - $toDelete[] = $key+1; - } - break; - - case 'tablerow_close': - - // Fix broken tables by adding missing cells - $moreCalls = array(); - while (++$lastCell < $this->maxCols) { - $moreCalls[] = array('tablecell_open', array(1, null, 1), $call[2]); - $moreCalls[] = array('cdata', array(''), $call[2]); - $moreCalls[] = array('tablecell_close', array(), $call[2]); - } - $moreCallsLength = count($moreCalls); - if($moreCallsLength) { - array_splice($this->tableCalls, $key, 0, $moreCalls); - $key += $moreCallsLength; - } - - if($this->countTableHeadRows == $lastRow) { - array_splice($this->tableCalls, $key+1, 0, array( - array('tablethead_close', array(), $call[2]))); - } - break; - - } - } - - // condense cdata - $cnt = count($this->tableCalls); - for( $key = 0; $key < $cnt; $key++){ - if($this->tableCalls[$key][0] == 'cdata'){ - $ckey = $key; - $key++; - while($this->tableCalls[$key][0] == 'cdata'){ - $this->tableCalls[$ckey][1][0] .= $this->tableCalls[$key][1][0]; - $toDelete[] = $key; - $key++; - } - continue; - } - } - - foreach ( $toDelete as $delete ) { - unset($this->tableCalls[$delete]); - } - $this->tableCalls = array_values($this->tableCalls); - } -} - - -/** - * Handler for paragraphs - * - * @author Harry Fuecks <hfuecks@gmail.com> - */ -class Doku_Handler_Block { - var $calls = array(); - var $skipEol = false; - var $inParagraph = false; - - // Blocks these should not be inside paragraphs - var $blockOpen = array( - 'header', - 'listu_open','listo_open','listitem_open','listcontent_open', - 'table_open','tablerow_open','tablecell_open','tableheader_open','tablethead_open', - 'quote_open', - 'code','file','hr','preformatted','rss', - 'htmlblock','phpblock', - 'footnote_open', - ); - - var $blockClose = array( - 'header', - 'listu_close','listo_close','listitem_close','listcontent_close', - 'table_close','tablerow_close','tablecell_close','tableheader_close','tablethead_close', - 'quote_close', - 'code','file','hr','preformatted','rss', - 'htmlblock','phpblock', - 'footnote_close', - ); - - // Stacks can contain paragraphs - var $stackOpen = array( - 'section_open', - ); - - var $stackClose = array( - 'section_close', - ); - - - /** - * Constructor. Adds loaded syntax plugins to the block and stack - * arrays - * - * @author Andreas Gohr <andi@splitbrain.org> - */ - function __construct(){ - global $DOKU_PLUGINS; - //check if syntax plugins were loaded - if(empty($DOKU_PLUGINS['syntax'])) return; - foreach($DOKU_PLUGINS['syntax'] as $n => $p){ - $ptype = $p->getPType(); - if($ptype == 'block'){ - $this->blockOpen[] = 'plugin_'.$n; - $this->blockClose[] = 'plugin_'.$n; - }elseif($ptype == 'stack'){ - $this->stackOpen[] = 'plugin_'.$n; - $this->stackClose[] = 'plugin_'.$n; - } - } - } - - function openParagraph($pos){ - if ($this->inParagraph) return; - $this->calls[] = array('p_open',array(), $pos); - $this->inParagraph = true; - $this->skipEol = true; - } - - /** - * Close a paragraph if needed - * - * This function makes sure there are no empty paragraphs on the stack - * - * @author Andreas Gohr <andi@splitbrain.org> - * - * @param string|integer $pos - */ - function closeParagraph($pos){ - if (!$this->inParagraph) return; - // look back if there was any content - we don't want empty paragraphs - $content = ''; - $ccount = count($this->calls); - for($i=$ccount-1; $i>=0; $i--){ - if($this->calls[$i][0] == 'p_open'){ - break; - }elseif($this->calls[$i][0] == 'cdata'){ - $content .= $this->calls[$i][1][0]; - }else{ - $content = 'found markup'; - break; - } - } - - if(trim($content)==''){ - //remove the whole paragraph - //array_splice($this->calls,$i); // <- this is much slower than the loop below - for($x=$ccount; $x>$i; $x--) array_pop($this->calls); - }else{ - // remove ending linebreaks in the paragraph - $i=count($this->calls)-1; - if ($this->calls[$i][0] == 'cdata') $this->calls[$i][1][0] = rtrim($this->calls[$i][1][0],DOKU_PARSER_EOL); - $this->calls[] = array('p_close',array(), $pos); - } - - $this->inParagraph = false; - $this->skipEol = true; - } - - function addCall($call) { - $key = count($this->calls); - if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) { - $this->calls[$key-1][1][0] .= $call[1][0]; - } else { - $this->calls[] = $call; - } - } - - // simple version of addCall, without checking cdata - function storeCall($call) { - $this->calls[] = $call; - } - - /** - * Processes the whole instruction stack to open and close paragraphs - * - * @author Harry Fuecks <hfuecks@gmail.com> - * @author Andreas Gohr <andi@splitbrain.org> - * - * @param array $calls - * - * @return array - */ - function process($calls) { - // open first paragraph - $this->openParagraph(0); - foreach ( $calls as $key => $call ) { - $cname = $call[0]; - if ($cname == 'plugin') { - $cname='plugin_'.$call[1][0]; - $plugin = true; - $plugin_open = (($call[1][2] == DOKU_LEXER_ENTER) || ($call[1][2] == DOKU_LEXER_SPECIAL)); - $plugin_close = (($call[1][2] == DOKU_LEXER_EXIT) || ($call[1][2] == DOKU_LEXER_SPECIAL)); - } else { - $plugin = false; - } - /* stack */ - if ( in_array($cname,$this->stackClose ) && (!$plugin || $plugin_close)) { - $this->closeParagraph($call[2]); - $this->storeCall($call); - $this->openParagraph($call[2]); - continue; - } - if ( in_array($cname,$this->stackOpen ) && (!$plugin || $plugin_open) ) { - $this->closeParagraph($call[2]); - $this->storeCall($call); - $this->openParagraph($call[2]); - continue; - } - /* block */ - // If it's a substition it opens and closes at the same call. - // To make sure next paragraph is correctly started, let close go first. - if ( in_array($cname, $this->blockClose) && (!$plugin || $plugin_close)) { - $this->closeParagraph($call[2]); - $this->storeCall($call); - $this->openParagraph($call[2]); - continue; - } - if ( in_array($cname, $this->blockOpen) && (!$plugin || $plugin_open)) { - $this->closeParagraph($call[2]); - $this->storeCall($call); - continue; - } - /* eol */ - if ( $cname == 'eol' ) { - // Check this isn't an eol instruction to skip... - if ( !$this->skipEol ) { - // Next is EOL => double eol => mark as paragraph - if ( isset($calls[$key+1]) && $calls[$key+1][0] == 'eol' ) { - $this->closeParagraph($call[2]); - $this->openParagraph($call[2]); - } else { - //if this is just a single eol make a space from it - $this->addCall(array('cdata',array(DOKU_PARSER_EOL), $call[2])); - } - } - continue; - } - /* normal */ - $this->addCall($call); - $this->skipEol = false; - } - // close last paragraph - $call = end($this->calls); - $this->closeParagraph($call[2]); - return $this->calls; - } -} - -//Setup VIM: ex: et ts=4 : diff --git a/wiki/inc/parser/lexer.php b/wiki/inc/parser/lexer.php deleted file mode 100644 index ba6a653..0000000 --- a/wiki/inc/parser/lexer.php +++ /dev/null @@ -1,614 +0,0 @@ -<?php -/** - * Author Markus Baker: http://www.lastcraft.com - * Version adapted from Simple Test: http://sourceforge.net/projects/simpletest/ - * For an intro to the Lexer see: - * https://web.archive.org/web/20120125041816/http://www.phppatterns.com/docs/develop/simple_test_lexer_notes - * @author Marcus Baker - * @package Doku - * @subpackage Lexer - * @version $Id: lexer.php,v 1.1 2005/03/23 23:14:09 harryf Exp $ - */ - -/** - * Init path constant - */ -if(!defined('DOKU_INC')) die('meh.'); - -/**#@+ - * lexer mode constant - */ -define("DOKU_LEXER_ENTER", 1); -define("DOKU_LEXER_MATCHED", 2); -define("DOKU_LEXER_UNMATCHED", 3); -define("DOKU_LEXER_EXIT", 4); -define("DOKU_LEXER_SPECIAL", 5); -/**#@-*/ - -/** - * Compounded regular expression. Any of - * the contained patterns could match and - * when one does it's label is returned. - * - * @package Doku - * @subpackage Lexer - */ -class Doku_LexerParallelRegex { - var $_patterns; - var $_labels; - var $_regex; - var $_case; - - /** - * Constructor. Starts with no patterns. - * - * @param boolean $case True for case sensitive, false - * for insensitive. - * @access public - */ - function __construct($case) { - $this->_case = $case; - $this->_patterns = array(); - $this->_labels = array(); - $this->_regex = null; - } - - /** - * Adds a pattern with an optional label. - * - * @param mixed $pattern Perl style regex. Must be UTF-8 - * encoded. If its a string, the (, ) - * lose their meaning unless they - * form part of a lookahead or - * lookbehind assertation. - * @param bool|string $label Label of regex to be returned - * on a match. Label must be ASCII - * @access public - */ - function addPattern($pattern, $label = true) { - $count = count($this->_patterns); - $this->_patterns[$count] = $pattern; - $this->_labels[$count] = $label; - $this->_regex = null; - } - - /** - * Attempts to match all patterns at once against a string. - * - * @param string $subject String to match against. - * @param string $match First matched portion of - * subject. - * @return boolean True on success. - * @access public - */ - function match($subject, &$match) { - if (count($this->_patterns) == 0) { - return false; - } - if (! preg_match($this->_getCompoundedRegex(), $subject, $matches)) { - $match = ""; - return false; - } - - $match = $matches[0]; - $size = count($matches); - for ($i = 1; $i < $size; $i++) { - if ($matches[$i] && isset($this->_labels[$i - 1])) { - return $this->_labels[$i - 1]; - } - } - return true; - } - - /** - * Attempts to split the string against all patterns at once - * - * @param string $subject String to match against. - * @param array $split The split result: array containing, pre-match, match & post-match strings - * @return boolean True on success. - * @access public - * - * @author Christopher Smith <chris@jalakai.co.uk> - */ - function split($subject, &$split) { - if (count($this->_patterns) == 0) { - return false; - } - - if (! preg_match($this->_getCompoundedRegex(), $subject, $matches)) { - if(function_exists('preg_last_error')){ - $err = preg_last_error(); - switch($err){ - case PREG_BACKTRACK_LIMIT_ERROR: - msg('A PCRE backtrack error occured. Try to increase the pcre.backtrack_limit in php.ini',-1); - break; - case PREG_RECURSION_LIMIT_ERROR: - msg('A PCRE recursion error occured. Try to increase the pcre.recursion_limit in php.ini',-1); - break; - case PREG_BAD_UTF8_ERROR: - msg('A PCRE UTF-8 error occured. This might be caused by a faulty plugin',-1); - break; - case PREG_INTERNAL_ERROR: - msg('A PCRE internal error occured. This might be caused by a faulty plugin',-1); - break; - } - } - - $split = array($subject, "", ""); - return false; - } - - $idx = count($matches)-2; - list($pre, $post) = preg_split($this->_patterns[$idx].$this->_getPerlMatchingFlags(), $subject, 2); - $split = array($pre, $matches[0], $post); - - return isset($this->_labels[$idx]) ? $this->_labels[$idx] : true; - } - - /** - * Compounds the patterns into a single - * regular expression separated with the - * "or" operator. Caches the regex. - * Will automatically escape (, ) and / tokens. - * - * @internal array $_patterns List of patterns in order. - * @return null|string - * @access private - */ - function _getCompoundedRegex() { - if ($this->_regex == null) { - $cnt = count($this->_patterns); - for ($i = 0; $i < $cnt; $i++) { - - /* - * decompose the input pattern into "(", "(?", ")", - * "[...]", "[]..]", "[^]..]", "[...[:...:]..]", "\x"... - * elements. - */ - preg_match_all('/\\\\.|' . - '\(\?|' . - '[()]|' . - '\[\^?\]?(?:\\\\.|\[:[^]]*:\]|[^]\\\\])*\]|' . - '[^[()\\\\]+/', $this->_patterns[$i], $elts); - - $pattern = ""; - $level = 0; - - foreach ($elts[0] as $elt) { - /* - * for "(", ")" remember the nesting level, add "\" - * only to the non-"(?" ones. - */ - - switch($elt) { - case '(': - $pattern .= '\('; - break; - case ')': - if ($level > 0) - $level--; /* closing (? */ - else - $pattern .= '\\'; - $pattern .= ')'; - break; - case '(?': - $level++; - $pattern .= '(?'; - break; - default: - if (substr($elt, 0, 1) == '\\') - $pattern .= $elt; - else - $pattern .= str_replace('/', '\/', $elt); - } - } - $this->_patterns[$i] = "($pattern)"; - } - $this->_regex = "/" . implode("|", $this->_patterns) . "/" . $this->_getPerlMatchingFlags(); - } - return $this->_regex; - } - - /** - * Accessor for perl regex mode flags to use. - * @return string Perl regex flags. - * @access private - */ - function _getPerlMatchingFlags() { - return ($this->_case ? "msS" : "msSi"); - } -} - -/** - * States for a stack machine. - * @package Lexer - * @subpackage Lexer - */ -class Doku_LexerStateStack { - var $_stack; - - /** - * Constructor. Starts in named state. - * @param string $start Starting state name. - * @access public - */ - function __construct($start) { - $this->_stack = array($start); - } - - /** - * Accessor for current state. - * @return string State. - * @access public - */ - function getCurrent() { - return $this->_stack[count($this->_stack) - 1]; - } - - /** - * Adds a state to the stack and sets it - * to be the current state. - * @param string $state New state. - * @access public - */ - function enter($state) { - array_push($this->_stack, $state); - } - - /** - * Leaves the current state and reverts - * to the previous one. - * @return boolean False if we drop off - * the bottom of the list. - * @access public - */ - function leave() { - if (count($this->_stack) == 1) { - return false; - } - array_pop($this->_stack); - return true; - } -} - -/** - * Accepts text and breaks it into tokens. - * Some optimisation to make the sure the - * content is only scanned by the PHP regex - * parser once. Lexer modes must not start - * with leading underscores. - * @package Doku - * @subpackage Lexer - */ -class Doku_Lexer { - var $_regexes; - var $_parser; - var $_mode; - var $_mode_handlers; - var $_case; - - /** - * Sets up the lexer in case insensitive matching - * by default. - * @param Doku_Parser $parser Handling strategy by - * reference. - * @param string $start Starting handler. - * @param boolean $case True for case sensitive. - * @access public - */ - function __construct($parser, $start = "accept", $case = false) { - $this->_case = $case; - /** @var Doku_LexerParallelRegex[] _regexes */ - $this->_regexes = array(); - $this->_parser = $parser; - $this->_mode = new Doku_LexerStateStack($start); - $this->_mode_handlers = array(); - } - - /** - * Adds a token search pattern for a particular - * parsing mode. The pattern does not change the - * current mode. - * @param string $pattern Perl style regex, but ( and ) - * lose the usual meaning. - * @param string $mode Should only apply this - * pattern when dealing with - * this type of input. - * @access public - */ - function addPattern($pattern, $mode = "accept") { - if (! isset($this->_regexes[$mode])) { - $this->_regexes[$mode] = new Doku_LexerParallelRegex($this->_case); - } - $this->_regexes[$mode]->addPattern($pattern); - } - - /** - * Adds a pattern that will enter a new parsing - * mode. Useful for entering parenthesis, strings, - * tags, etc. - * @param string $pattern Perl style regex, but ( and ) - * lose the usual meaning. - * @param string $mode Should only apply this - * pattern when dealing with - * this type of input. - * @param string $new_mode Change parsing to this new - * nested mode. - * @access public - */ - function addEntryPattern($pattern, $mode, $new_mode) { - if (! isset($this->_regexes[$mode])) { - $this->_regexes[$mode] = new Doku_LexerParallelRegex($this->_case); - } - $this->_regexes[$mode]->addPattern($pattern, $new_mode); - } - - /** - * Adds a pattern that will exit the current mode - * and re-enter the previous one. - * @param string $pattern Perl style regex, but ( and ) - * lose the usual meaning. - * @param string $mode Mode to leave. - * @access public - */ - function addExitPattern($pattern, $mode) { - if (! isset($this->_regexes[$mode])) { - $this->_regexes[$mode] = new Doku_LexerParallelRegex($this->_case); - } - $this->_regexes[$mode]->addPattern($pattern, "__exit"); - } - - /** - * Adds a pattern that has a special mode. Acts as an entry - * and exit pattern in one go, effectively calling a special - * parser handler for this token only. - * @param string $pattern Perl style regex, but ( and ) - * lose the usual meaning. - * @param string $mode Should only apply this - * pattern when dealing with - * this type of input. - * @param string $special Use this mode for this one token. - * @access public - */ - function addSpecialPattern($pattern, $mode, $special) { - if (! isset($this->_regexes[$mode])) { - $this->_regexes[$mode] = new Doku_LexerParallelRegex($this->_case); - } - $this->_regexes[$mode]->addPattern($pattern, "_$special"); - } - - /** - * Adds a mapping from a mode to another handler. - * @param string $mode Mode to be remapped. - * @param string $handler New target handler. - * @access public - */ - function mapHandler($mode, $handler) { - $this->_mode_handlers[$mode] = $handler; - } - - /** - * Splits the page text into tokens. Will fail - * if the handlers report an error or if no - * content is consumed. If successful then each - * unparsed and parsed token invokes a call to the - * held listener. - * @param string $raw Raw HTML text. - * @return boolean True on success, else false. - * @access public - */ - function parse($raw) { - if (! isset($this->_parser)) { - return false; - } - $initialLength = strlen($raw); - $length = $initialLength; - $pos = 0; - while (is_array($parsed = $this->_reduce($raw))) { - list($unmatched, $matched, $mode) = $parsed; - $currentLength = strlen($raw); - $matchPos = $initialLength - $currentLength - strlen($matched); - if (! $this->_dispatchTokens($unmatched, $matched, $mode, $pos, $matchPos)) { - return false; - } - if ($currentLength == $length) { - return false; - } - $length = $currentLength; - $pos = $initialLength - $currentLength; - } - if (!$parsed) { - return false; - } - return $this->_invokeParser($raw, DOKU_LEXER_UNMATCHED, $pos); - } - - /** - * Sends the matched token and any leading unmatched - * text to the parser changing the lexer to a new - * mode if one is listed. - * @param string $unmatched Unmatched leading portion. - * @param string $matched Actual token match. - * @param bool|string $mode Mode after match. A boolean - * false mode causes no change. - * @param int $initialPos - * @param int $matchPos - * Current byte index location in raw doc - * thats being parsed - * @return boolean False if there was any error - * from the parser. - * @access private - */ - function _dispatchTokens($unmatched, $matched, $mode = false, $initialPos, $matchPos) { - if (! $this->_invokeParser($unmatched, DOKU_LEXER_UNMATCHED, $initialPos) ){ - return false; - } - if ($this->_isModeEnd($mode)) { - if (! $this->_invokeParser($matched, DOKU_LEXER_EXIT, $matchPos)) { - return false; - } - return $this->_mode->leave(); - } - if ($this->_isSpecialMode($mode)) { - $this->_mode->enter($this->_decodeSpecial($mode)); - if (! $this->_invokeParser($matched, DOKU_LEXER_SPECIAL, $matchPos)) { - return false; - } - return $this->_mode->leave(); - } - if (is_string($mode)) { - $this->_mode->enter($mode); - return $this->_invokeParser($matched, DOKU_LEXER_ENTER, $matchPos); - } - return $this->_invokeParser($matched, DOKU_LEXER_MATCHED, $matchPos); - } - - /** - * Tests to see if the new mode is actually to leave - * the current mode and pop an item from the matching - * mode stack. - * @param string $mode Mode to test. - * @return boolean True if this is the exit mode. - * @access private - */ - function _isModeEnd($mode) { - return ($mode === "__exit"); - } - - /** - * Test to see if the mode is one where this mode - * is entered for this token only and automatically - * leaves immediately afterwoods. - * @param string $mode Mode to test. - * @return boolean True if this is the exit mode. - * @access private - */ - function _isSpecialMode($mode) { - return (strncmp($mode, "_", 1) == 0); - } - - /** - * Strips the magic underscore marking single token - * modes. - * @param string $mode Mode to decode. - * @return string Underlying mode name. - * @access private - */ - function _decodeSpecial($mode) { - return substr($mode, 1); - } - - /** - * Calls the parser method named after the current - * mode. Empty content will be ignored. The lexer - * has a parser handler for each mode in the lexer. - * @param string $content Text parsed. - * @param boolean $is_match Token is recognised rather - * than unparsed data. - * @param int $pos Current byte index location in raw doc - * thats being parsed - * @return bool - * @access private - */ - function _invokeParser($content, $is_match, $pos) { - if (($content === "") || ($content === false)) { - return true; - } - $handler = $this->_mode->getCurrent(); - if (isset($this->_mode_handlers[$handler])) { - $handler = $this->_mode_handlers[$handler]; - } - - // modes starting with plugin_ are all handled by the same - // handler but with an additional parameter - if(substr($handler,0,7)=='plugin_'){ - list($handler,$plugin) = explode('_',$handler,2); - return $this->_parser->$handler($content, $is_match, $pos, $plugin); - } - - return $this->_parser->$handler($content, $is_match, $pos); - } - - /** - * Tries to match a chunk of text and if successful - * removes the recognised chunk and any leading - * unparsed data. Empty strings will not be matched. - * @param string $raw The subject to parse. This is the - * content that will be eaten. - * @return array Three item list of unparsed - * content followed by the - * recognised token and finally the - * action the parser is to take. - * True if no match, false if there - * is a parsing error. - * @access private - */ - function _reduce(&$raw) { - if (! isset($this->_regexes[$this->_mode->getCurrent()])) { - return false; - } - if ($raw === "") { - return true; - } - if ($action = $this->_regexes[$this->_mode->getCurrent()]->split($raw, $split)) { - list($unparsed, $match, $raw) = $split; - return array($unparsed, $match, $action); - } - return true; - } -} - -/** - * Escapes regex characters other than (, ) and / - * - * @TODO - * - * @param string $str - * - * @return mixed - */ -function Doku_Lexer_Escape($str) { - //$str = addslashes($str); - $chars = array( - '/\\\\/', - '/\./', - '/\+/', - '/\*/', - '/\?/', - '/\[/', - '/\^/', - '/\]/', - '/\$/', - '/\{/', - '/\}/', - '/\=/', - '/\!/', - '/\</', - '/\>/', - '/\|/', - '/\:/' - ); - - $escaped = array( - '\\\\\\\\', - '\.', - '\+', - '\*', - '\?', - '\[', - '\^', - '\]', - '\$', - '\{', - '\}', - '\=', - '\!', - '\<', - '\>', - '\|', - '\:' - ); - return preg_replace($chars, $escaped, $str); -} - -//Setup VIM: ex: et ts=4 sw=4 : diff --git a/wiki/inc/parser/metadata.php b/wiki/inc/parser/metadata.php deleted file mode 100644 index 9b1b5c9..0000000 --- a/wiki/inc/parser/metadata.php +++ /dev/null @@ -1,694 +0,0 @@ -<?php -/** - * Renderer for metadata - * - * @author Esther Brunner <wikidesign@gmail.com> - */ -if(!defined('DOKU_INC')) die('meh.'); - -if(!defined('DOKU_LF')) { - // Some whitespace to help View > Source - define ('DOKU_LF', "\n"); -} - -if(!defined('DOKU_TAB')) { - // Some whitespace to help View > Source - define ('DOKU_TAB', "\t"); -} - -/** - * The MetaData Renderer - * - * Metadata is additional information about a DokuWiki page that gets extracted mainly from the page's content - * but also it's own filesystem data (like the creation time). All metadata is stored in the fields $meta and - * $persistent. - * - * Some simplified rendering to $doc is done to gather the page's (text-only) abstract. - */ -class Doku_Renderer_metadata extends Doku_Renderer { - /** the approximate byte lenght to capture for the abstract */ - const ABSTRACT_LEN = 250; - - /** the maximum UTF8 character length for the abstract */ - const ABSTRACT_MAX = 500; - - /** @var array transient meta data, will be reset on each rendering */ - public $meta = array(); - - /** @var array persistent meta data, will be kept until explicitly deleted */ - public $persistent = array(); - - /** @var array the list of headers used to create unique link ids */ - protected $headers = array(); - - /** @var string temporary $doc store */ - protected $store = ''; - - /** @var string keeps the first image reference */ - protected $firstimage = ''; - - /** @var bool determines if enough data for the abstract was collected, yet */ - public $capture = true; - - /** @var int number of bytes captured for abstract */ - protected $captured = 0; - - /** - * Returns the format produced by this renderer. - * - * @return string always 'metadata' - */ - function getFormat() { - return 'metadata'; - } - - /** - * Initialize the document - * - * Sets up some of the persistent info about the page if it doesn't exist, yet. - */ - function document_start() { - global $ID; - - $this->headers = array(); - - // external pages are missing create date - if(!$this->persistent['date']['created']) { - $this->persistent['date']['created'] = filectime(wikiFN($ID)); - } - if(!isset($this->persistent['user'])) { - $this->persistent['user'] = ''; - } - if(!isset($this->persistent['creator'])) { - $this->persistent['creator'] = ''; - } - // reset metadata to persistent values - $this->meta = $this->persistent; - } - - /** - * Finalize the document - * - * Stores collected data in the metadata - */ - function document_end() { - global $ID; - - // store internal info in metadata (notoc,nocache) - $this->meta['internal'] = $this->info; - - if(!isset($this->meta['description']['abstract'])) { - // cut off too long abstracts - $this->doc = trim($this->doc); - if(strlen($this->doc) > self::ABSTRACT_MAX) { - $this->doc = utf8_substr($this->doc, 0, self::ABSTRACT_MAX).'…'; - } - $this->meta['description']['abstract'] = $this->doc; - } - - $this->meta['relation']['firstimage'] = $this->firstimage; - - if(!isset($this->meta['date']['modified'])) { - $this->meta['date']['modified'] = filemtime(wikiFN($ID)); - } - - } - - /** - * Render plain text data - * - * This function takes care of the amount captured data and will stop capturing when - * enough abstract data is available - * - * @param $text - */ - function cdata($text) { - if(!$this->capture) return; - - $this->doc .= $text; - - $this->captured += strlen($text); - if($this->captured > self::ABSTRACT_LEN) $this->capture = false; - } - - /** - * Add an item to the TOC - * - * @param string $id the hash link - * @param string $text the text to display - * @param int $level the nesting level - */ - function toc_additem($id, $text, $level) { - global $conf; - - //only add items within configured levels - if($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']) { - // the TOC is one of our standard ul list arrays ;-) - $this->meta['description']['tableofcontents'][] = array( - 'hid' => $id, - 'title' => $text, - 'type' => 'ul', - 'level' => $level - $conf['toptoclevel'] + 1 - ); - } - - } - - /** - * Render a heading - * - * @param string $text the text to display - * @param int $level header level - * @param int $pos byte position in the original source - */ - function header($text, $level, $pos) { - if(!isset($this->meta['title'])) $this->meta['title'] = $text; - - // add the header to the TOC - $hid = $this->_headerToLink($text, true); - $this->toc_additem($hid, $text, $level); - - // add to summary - $this->cdata(DOKU_LF.$text.DOKU_LF); - } - - /** - * Open a paragraph - */ - function p_open() { - $this->cdata(DOKU_LF); - } - - /** - * Close a paragraph - */ - function p_close() { - $this->cdata(DOKU_LF); - } - - /** - * Create a line break - */ - function linebreak() { - $this->cdata(DOKU_LF); - } - - /** - * Create a horizontal line - */ - function hr() { - $this->cdata(DOKU_LF.'----------'.DOKU_LF); - } - - /** - * Callback for footnote start syntax - * - * All following content will go to the footnote instead of - * the document. To achieve this the previous rendered content - * is moved to $store and $doc is cleared - * - * @author Andreas Gohr <andi@splitbrain.org> - */ - function footnote_open() { - if($this->capture) { - // move current content to store and record footnote - $this->store = $this->doc; - $this->doc = ''; - } - } - - /** - * Callback for footnote end syntax - * - * All rendered content is moved to the $footnotes array and the old - * content is restored from $store again - * - * @author Andreas Gohr - */ - function footnote_close() { - if($this->capture) { - // restore old content - $this->doc = $this->store; - $this->store = ''; - } - } - - /** - * Open an unordered list - */ - function listu_open() { - $this->cdata(DOKU_LF); - } - - /** - * Open an ordered list - */ - function listo_open() { - $this->cdata(DOKU_LF); - } - - /** - * Open a list item - * - * @param int $level the nesting level - * @param bool $node true when a node; false when a leaf - */ - function listitem_open($level,$node=false) { - $this->cdata(str_repeat(DOKU_TAB, $level).'* '); - } - - /** - * Close a list item - */ - function listitem_close() { - $this->cdata(DOKU_LF); - } - - /** - * Output preformatted text - * - * @param string $text - */ - function preformatted($text) { - $this->cdata($text); - } - - /** - * Start a block quote - */ - function quote_open() { - $this->cdata(DOKU_LF.DOKU_TAB.'"'); - } - - /** - * Stop a block quote - */ - function quote_close() { - $this->cdata('"'.DOKU_LF); - } - - /** - * Display text as file content, optionally syntax highlighted - * - * @param string $text text to show - * @param string $lang programming language to use for syntax highlighting - * @param string $file file path label - */ - function file($text, $lang = null, $file = null) { - $this->cdata(DOKU_LF.$text.DOKU_LF); - } - - /** - * Display text as code content, optionally syntax highlighted - * - * @param string $text text to show - * @param string $language programming language to use for syntax highlighting - * @param string $file file path label - */ - function code($text, $language = null, $file = null) { - $this->cdata(DOKU_LF.$text.DOKU_LF); - } - - /** - * Format an acronym - * - * Uses $this->acronyms - * - * @param string $acronym - */ - function acronym($acronym) { - $this->cdata($acronym); - } - - /** - * Format a smiley - * - * Uses $this->smiley - * - * @param string $smiley - */ - function smiley($smiley) { - $this->cdata($smiley); - } - - /** - * Format an entity - * - * Entities are basically small text replacements - * - * Uses $this->entities - * - * @param string $entity - */ - function entity($entity) { - $this->cdata($entity); - } - - /** - * Typographically format a multiply sign - * - * Example: ($x=640, $y=480) should result in "640×480" - * - * @param string|int $x first value - * @param string|int $y second value - */ - function multiplyentity($x, $y) { - $this->cdata($x.'×'.$y); - } - - /** - * Render an opening single quote char (language specific) - */ - function singlequoteopening() { - global $lang; - $this->cdata($lang['singlequoteopening']); - } - - /** - * Render a closing single quote char (language specific) - */ - function singlequoteclosing() { - global $lang; - $this->cdata($lang['singlequoteclosing']); - } - - /** - * Render an apostrophe char (language specific) - */ - function apostrophe() { - global $lang; - $this->cdata($lang['apostrophe']); - } - - /** - * Render an opening double quote char (language specific) - */ - function doublequoteopening() { - global $lang; - $this->cdata($lang['doublequoteopening']); - } - - /** - * Render an closinging double quote char (language specific) - */ - function doublequoteclosing() { - global $lang; - $this->cdata($lang['doublequoteclosing']); - } - - /** - * Render a CamelCase link - * - * @param string $link The link name - * @see http://en.wikipedia.org/wiki/CamelCase - */ - function camelcaselink($link) { - $this->internallink($link, $link); - } - - /** - * Render a page local link - * - * @param string $hash hash link identifier - * @param string $name name for the link - */ - function locallink($hash, $name = null) { - if(is_array($name)) { - $this->_firstimage($name['src']); - if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); - } - } - - /** - * keep track of internal links in $this->meta['relation']['references'] - * - * @param string $id page ID to link to. eg. 'wiki:syntax' - * @param string|array|null $name name for the link, array for media file - */ - function internallink($id, $name = null) { - global $ID; - - if(is_array($name)) { - $this->_firstimage($name['src']); - if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); - } - - $parts = explode('?', $id, 2); - if(count($parts) === 2) { - $id = $parts[0]; - } - - $default = $this->_simpleTitle($id); - - // first resolve and clean up the $id - resolve_pageid(getNS($ID), $id, $exists); - @list($page) = explode('#', $id, 2); - - // set metadata - $this->meta['relation']['references'][$page] = $exists; - // $data = array('relation' => array('isreferencedby' => array($ID => true))); - // p_set_metadata($id, $data); - - // add link title to summary - if($this->capture) { - $name = $this->_getLinkTitle($name, $default, $id); - $this->doc .= $name; - } - } - - /** - * Render an external link - * - * @param string $url full URL with scheme - * @param string|array|null $name name for the link, array for media file - */ - function externallink($url, $name = null) { - if(is_array($name)) { - $this->_firstimage($name['src']); - if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); - } - - if($this->capture) { - $this->doc .= $this->_getLinkTitle($name, '<'.$url.'>'); - } - } - - /** - * Render an interwiki link - * - * You may want to use $this->_resolveInterWiki() here - * - * @param string $match original link - probably not much use - * @param string|array $name name for the link, array for media file - * @param string $wikiName indentifier (shortcut) for the remote wiki - * @param string $wikiUri the fragment parsed from the original link - */ - function interwikilink($match, $name = null, $wikiName, $wikiUri) { - if(is_array($name)) { - $this->_firstimage($name['src']); - if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); - } - - if($this->capture) { - list($wikiUri) = explode('#', $wikiUri, 2); - $name = $this->_getLinkTitle($name, $wikiUri); - $this->doc .= $name; - } - } - - /** - * Link to windows share - * - * @param string $url the link - * @param string|array $name name for the link, array for media file - */ - function windowssharelink($url, $name = null) { - if(is_array($name)) { - $this->_firstimage($name['src']); - if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); - } - - if($this->capture) { - if($name) $this->doc .= $name; - else $this->doc .= '<'.$url.'>'; - } - } - - /** - * Render a linked E-Mail Address - * - * Should honor $conf['mailguard'] setting - * - * @param string $address Email-Address - * @param string|array $name name for the link, array for media file - */ - function emaillink($address, $name = null) { - if(is_array($name)) { - $this->_firstimage($name['src']); - if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); - } - - if($this->capture) { - if($name) $this->doc .= $name; - else $this->doc .= '<'.$address.'>'; - } - } - - /** - * Render an internal media file - * - * @param string $src media ID - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - * @param string $linking linkonly|detail|nolink - */ - function internalmedia($src, $title = null, $align = null, $width = null, - $height = null, $cache = null, $linking = null) { - if($this->capture && $title) $this->doc .= '['.$title.']'; - $this->_firstimage($src); - $this->_recordMediaUsage($src); - } - - /** - * Render an external media file - * - * @param string $src full media URL - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - * @param string $linking linkonly|detail|nolink - */ - function externalmedia($src, $title = null, $align = null, $width = null, - $height = null, $cache = null, $linking = null) { - if($this->capture && $title) $this->doc .= '['.$title.']'; - $this->_firstimage($src); - } - - /** - * Render the output of an RSS feed - * - * @param string $url URL of the feed - * @param array $params Finetuning of the output - */ - function rss($url, $params) { - $this->meta['relation']['haspart'][$url] = true; - - $this->meta['date']['valid']['age'] = - isset($this->meta['date']['valid']['age']) ? - min($this->meta['date']['valid']['age'], $params['refresh']) : - $params['refresh']; - } - - #region Utils - - /** - * Removes any Namespace from the given name but keeps - * casing and special chars - * - * @author Andreas Gohr <andi@splitbrain.org> - * - * @param string $name - * - * @return mixed|string - */ - function _simpleTitle($name) { - global $conf; - - if(is_array($name)) return ''; - - if($conf['useslash']) { - $nssep = '[:;/]'; - } else { - $nssep = '[:;]'; - } - $name = preg_replace('!.*'.$nssep.'!', '', $name); - //if there is a hash we use the anchor name only - $name = preg_replace('!.*#!', '', $name); - return $name; - } - - /** - * Creates a linkid from a headline - * - * @author Andreas Gohr <andi@splitbrain.org> - * @param string $title The headline title - * @param boolean $create Create a new unique ID? - * @return string - */ - function _headerToLink($title, $create = false) { - if($create) { - return sectionID($title, $this->headers); - } else { - $check = false; - return sectionID($title, $check); - } - } - - /** - * Construct a title and handle images in titles - * - * @author Harry Fuecks <hfuecks@gmail.com> - * @param string|array|null $title either string title or media array - * @param string $default default title if nothing else is found - * @param null|string $id linked page id (used to extract title from first heading) - * @return string title text - */ - function _getLinkTitle($title, $default, $id = null) { - if(is_array($title)) { - if($title['title']) { - return '['.$title['title'].']'; - } else { - return $default; - } - } else if(is_null($title) || trim($title) == '') { - if(useHeading('content') && $id) { - $heading = p_get_first_heading($id, METADATA_DONT_RENDER); - if($heading) return $heading; - } - return $default; - } else { - return $title; - } - } - - /** - * Remember first image - * - * @param string $src image URL or ID - */ - function _firstimage($src) { - if($this->firstimage) return; - global $ID; - - list($src) = explode('#', $src, 2); - if(!media_isexternal($src)) { - resolve_mediaid(getNS($ID), $src, $exists); - } - if(preg_match('/.(jpe?g|gif|png)$/i', $src)) { - $this->firstimage = $src; - } - } - - /** - * Store list of used media files in metadata - * - * @param string $src media ID - */ - function _recordMediaUsage($src) { - global $ID; - - list ($src) = explode('#', $src, 2); - if(media_isexternal($src)) return; - resolve_mediaid(getNS($ID), $src, $exists); - $this->meta['relation']['media'][$src] = $exists; - } - - #endregion -} - -//Setup VIM: ex: et ts=4 : diff --git a/wiki/inc/parser/parser.php b/wiki/inc/parser/parser.php deleted file mode 100644 index 8cff2b8..0000000 --- a/wiki/inc/parser/parser.php +++ /dev/null @@ -1,1034 +0,0 @@ -<?php -if(!defined('DOKU_INC')) die('meh.'); -require_once DOKU_INC . 'inc/parser/lexer.php'; -require_once DOKU_INC . 'inc/parser/handler.php'; - - -/** - * Define various types of modes used by the parser - they are used to - * populate the list of modes another mode accepts - */ -global $PARSER_MODES; -$PARSER_MODES = array( - // containers are complex modes that can contain many other modes - // hr breaks the principle but they shouldn't be used in tables / lists - // so they are put here - 'container' => array('listblock','table','quote','hr'), - - // some mode are allowed inside the base mode only - 'baseonly' => array('header'), - - // modes for styling text -- footnote behaves similar to styling - 'formatting' => array('strong', 'emphasis', 'underline', 'monospace', - 'subscript', 'superscript', 'deleted', 'footnote'), - - // modes where the token is simply replaced - they can not contain any - // other modes - 'substition' => array('acronym','smiley','wordblock','entity', - 'camelcaselink', 'internallink','media', - 'externallink','linebreak','emaillink', - 'windowssharelink','filelink','notoc', - 'nocache','multiplyentity','quotes','rss'), - - // modes which have a start and end token but inside which - // no other modes should be applied - 'protected' => array('preformatted','code','file','php','html','htmlblock','phpblock'), - - // inside this mode no wiki markup should be applied but lineendings - // and whitespace isn't preserved - 'disabled' => array('unformatted'), - - // used to mark paragraph boundaries - 'paragraphs' => array('eol') -); - -//------------------------------------------------------------------- - -/** - * Sets up the Lexer with modes and points it to the Handler - * For an intro to the Lexer see: wiki:parser - */ -class Doku_Parser { - - var $Handler; - - /** - * @var Doku_Lexer $Lexer - */ - var $Lexer; - - var $modes = array(); - - var $connected = false; - - /** - * @param Doku_Parser_Mode_base $BaseMode - */ - function addBaseMode($BaseMode) { - $this->modes['base'] = $BaseMode; - if ( !$this->Lexer ) { - $this->Lexer = new Doku_Lexer($this->Handler,'base', true); - } - $this->modes['base']->Lexer = $this->Lexer; - } - - /** - * PHP preserves order of associative elements - * Mode sequence is important - * - * @param string $name - * @param Doku_Parser_Mode_Interface $Mode - */ - function addMode($name, Doku_Parser_Mode_Interface $Mode) { - if ( !isset($this->modes['base']) ) { - $this->addBaseMode(new Doku_Parser_Mode_base()); - } - $Mode->Lexer = $this->Lexer; - $this->modes[$name] = $Mode; - } - - function connectModes() { - - if ( $this->connected ) { - return; - } - - foreach ( array_keys($this->modes) as $mode ) { - - // Base isn't connected to anything - if ( $mode == 'base' ) { - continue; - } - $this->modes[$mode]->preConnect(); - - foreach ( array_keys($this->modes) as $cm ) { - - if ( $this->modes[$cm]->accepts($mode) ) { - $this->modes[$mode]->connectTo($cm); - } - - } - - $this->modes[$mode]->postConnect(); - } - - $this->connected = true; - } - - function parse($doc) { - if ( $this->Lexer ) { - $this->connectModes(); - // Normalize CRs and pad doc - $doc = "\n".str_replace("\r\n","\n",$doc)."\n"; - $this->Lexer->parse($doc); - $this->Handler->_finalize(); - return $this->Handler->calls; - } else { - return false; - } - } - -} - -//------------------------------------------------------------------- - -/** - * Class Doku_Parser_Mode_Interface - * - * Defines a mode (syntax component) in the Parser - */ -interface Doku_Parser_Mode_Interface { - /** - * returns a number used to determine in which order modes are added - */ - public function getSort(); - - /** - * Called before any calls to connectTo - * @return void - */ - function preConnect(); - - /** - * Connects the mode - * - * @param string $mode - * @return void - */ - function connectTo($mode); - - /** - * Called after all calls to connectTo - * @return void - */ - function postConnect(); - - /** - * Check if given mode is accepted inside this mode - * - * @param string $mode - * @return bool - */ - function accepts($mode); -} - -/** - * This class and all the subclasses below are used to reduce the effort required to register - * modes with the Lexer. - * - * @author Harry Fuecks <hfuecks@gmail.com> - */ -class Doku_Parser_Mode implements Doku_Parser_Mode_Interface { - /** - * @var Doku_Lexer $Lexer - */ - var $Lexer; - var $allowedModes = array(); - - function getSort() { - trigger_error('getSort() not implemented in '.get_class($this), E_USER_WARNING); - } - - function preConnect() {} - function connectTo($mode) {} - function postConnect() {} - function accepts($mode) { - return in_array($mode, (array) $this->allowedModes ); - } -} - -/** - * Basically the same as Doku_Parser_Mode but extends from DokuWiki_Plugin - * - * Adds additional functions to syntax plugins - */ -class Doku_Parser_Mode_Plugin extends DokuWiki_Plugin implements Doku_Parser_Mode_Interface { - /** - * @var Doku_Lexer $Lexer - */ - var $Lexer; - var $allowedModes = array(); - - /** - * Sort for applying this mode - * - * @return int - */ - function getSort() { - trigger_error('getSort() not implemented in '.get_class($this), E_USER_WARNING); - } - - function preConnect() {} - function connectTo($mode) {} - function postConnect() {} - function accepts($mode) { - return in_array($mode, (array) $this->allowedModes ); - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_base extends Doku_Parser_Mode { - - function __construct() { - global $PARSER_MODES; - - $this->allowedModes = array_merge ( - $PARSER_MODES['container'], - $PARSER_MODES['baseonly'], - $PARSER_MODES['paragraphs'], - $PARSER_MODES['formatting'], - $PARSER_MODES['substition'], - $PARSER_MODES['protected'], - $PARSER_MODES['disabled'] - ); - } - - function getSort() { - return 0; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_footnote extends Doku_Parser_Mode { - - function __construct() { - global $PARSER_MODES; - - $this->allowedModes = array_merge ( - $PARSER_MODES['container'], - $PARSER_MODES['formatting'], - $PARSER_MODES['substition'], - $PARSER_MODES['protected'], - $PARSER_MODES['disabled'] - ); - - unset($this->allowedModes[array_search('footnote', $this->allowedModes)]); - } - - function connectTo($mode) { - $this->Lexer->addEntryPattern( - '\x28\x28(?=.*\x29\x29)',$mode,'footnote' - ); - } - - function postConnect() { - $this->Lexer->addExitPattern( - '\x29\x29','footnote' - ); - } - - function getSort() { - return 150; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_header extends Doku_Parser_Mode { - - function connectTo($mode) { - //we're not picky about the closing ones, two are enough - $this->Lexer->addSpecialPattern( - '[ \t]*={2,}[^\n]+={2,}[ \t]*(?=\n)', - $mode, - 'header' - ); - } - - function getSort() { - return 50; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_notoc extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc'); - } - - function getSort() { - return 30; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_nocache extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addSpecialPattern('~~NOCACHE~~',$mode,'nocache'); - } - - function getSort() { - return 40; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_linebreak extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addSpecialPattern('\x5C{2}(?:[ \t]|(?=\n))',$mode,'linebreak'); - } - - function getSort() { - return 140; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_eol extends Doku_Parser_Mode { - - function connectTo($mode) { - $badModes = array('listblock','table'); - if ( in_array($mode, $badModes) ) { - return; - } - // see FS#1652, pattern extended to swallow preceding whitespace to avoid issues with lines that only contain whitespace - $this->Lexer->addSpecialPattern('(?:^[ \t]*)?\n',$mode,'eol'); - } - - function getSort() { - return 370; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_hr extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)',$mode,'hr'); - } - - function getSort() { - return 160; - } -} - -//------------------------------------------------------------------- -/** - * This class sets the markup for bold (=strong), - * italic (=emphasis), underline etc. - */ -class Doku_Parser_Mode_formatting extends Doku_Parser_Mode { - var $type; - - var $formatting = array ( - 'strong' => array ( - 'entry'=>'\*\*(?=.*\*\*)', - 'exit'=>'\*\*', - 'sort'=>70 - ), - - 'emphasis'=> array ( - 'entry'=>'//(?=[^\x00]*[^:])', //hack for bugs #384 #763 #1468 - 'exit'=>'//', - 'sort'=>80 - ), - - 'underline'=> array ( - 'entry'=>'__(?=.*__)', - 'exit'=>'__', - 'sort'=>90 - ), - - 'monospace'=> array ( - 'entry'=>'\x27\x27(?=.*\x27\x27)', - 'exit'=>'\x27\x27', - 'sort'=>100 - ), - - 'subscript'=> array ( - 'entry'=>'<sub>(?=.*</sub>)', - 'exit'=>'</sub>', - 'sort'=>110 - ), - - 'superscript'=> array ( - 'entry'=>'<sup>(?=.*</sup>)', - 'exit'=>'</sup>', - 'sort'=>120 - ), - - 'deleted'=> array ( - 'entry'=>'<del>(?=.*</del>)', - 'exit'=>'</del>', - 'sort'=>130 - ), - ); - - /** - * @param string $type - */ - function __construct($type) { - global $PARSER_MODES; - - if ( !array_key_exists($type, $this->formatting) ) { - trigger_error('Invalid formatting type '.$type, E_USER_WARNING); - } - - $this->type = $type; - - // formatting may contain other formatting but not it self - $modes = $PARSER_MODES['formatting']; - $key = array_search($type, $modes); - if ( is_int($key) ) { - unset($modes[$key]); - } - - $this->allowedModes = array_merge ( - $modes, - $PARSER_MODES['substition'], - $PARSER_MODES['disabled'] - ); - } - - function connectTo($mode) { - - // Can't nest formatting in itself - if ( $mode == $this->type ) { - return; - } - - $this->Lexer->addEntryPattern( - $this->formatting[$this->type]['entry'], - $mode, - $this->type - ); - } - - function postConnect() { - - $this->Lexer->addExitPattern( - $this->formatting[$this->type]['exit'], - $this->type - ); - - } - - function getSort() { - return $this->formatting[$this->type]['sort']; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_listblock extends Doku_Parser_Mode { - - function __construct() { - global $PARSER_MODES; - - $this->allowedModes = array_merge ( - $PARSER_MODES['formatting'], - $PARSER_MODES['substition'], - $PARSER_MODES['disabled'], - $PARSER_MODES['protected'] #XXX new - ); - - // $this->allowedModes[] = 'footnote'; - } - - function connectTo($mode) { - $this->Lexer->addEntryPattern('[ \t]*\n {2,}[\-\*]',$mode,'listblock'); - $this->Lexer->addEntryPattern('[ \t]*\n\t{1,}[\-\*]',$mode,'listblock'); - - $this->Lexer->addPattern('\n {2,}[\-\*]','listblock'); - $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock'); - - } - - function postConnect() { - $this->Lexer->addExitPattern('\n','listblock'); - } - - function getSort() { - return 10; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_table extends Doku_Parser_Mode { - - function __construct() { - global $PARSER_MODES; - - $this->allowedModes = array_merge ( - $PARSER_MODES['formatting'], - $PARSER_MODES['substition'], - $PARSER_MODES['disabled'], - $PARSER_MODES['protected'] - ); - } - - function connectTo($mode) { - $this->Lexer->addEntryPattern('[\t ]*\n\^',$mode,'table'); - $this->Lexer->addEntryPattern('[\t ]*\n\|',$mode,'table'); - } - - function postConnect() { - $this->Lexer->addPattern('\n\^','table'); - $this->Lexer->addPattern('\n\|','table'); - $this->Lexer->addPattern('[\t ]*:::[\t ]*(?=[\|\^])','table'); - $this->Lexer->addPattern('[\t ]+','table'); - $this->Lexer->addPattern('\^','table'); - $this->Lexer->addPattern('\|','table'); - $this->Lexer->addExitPattern('\n','table'); - } - - function getSort() { - return 60; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_unformatted extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addEntryPattern('<nowiki>(?=.*</nowiki>)',$mode,'unformatted'); - $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt'); - } - - function postConnect() { - $this->Lexer->addExitPattern('</nowiki>','unformatted'); - $this->Lexer->addExitPattern('%%','unformattedalt'); - $this->Lexer->mapHandler('unformattedalt','unformatted'); - } - - function getSort() { - return 170; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_php extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addEntryPattern('<php>(?=.*</php>)',$mode,'php'); - $this->Lexer->addEntryPattern('<PHP>(?=.*</PHP>)',$mode,'phpblock'); - } - - function postConnect() { - $this->Lexer->addExitPattern('</php>','php'); - $this->Lexer->addExitPattern('</PHP>','phpblock'); - } - - function getSort() { - return 180; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_html extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addEntryPattern('<html>(?=.*</html>)',$mode,'html'); - $this->Lexer->addEntryPattern('<HTML>(?=.*</HTML>)',$mode,'htmlblock'); - } - - function postConnect() { - $this->Lexer->addExitPattern('</html>','html'); - $this->Lexer->addExitPattern('</HTML>','htmlblock'); - } - - function getSort() { - return 190; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_preformatted extends Doku_Parser_Mode { - - function connectTo($mode) { - // Has hard coded awareness of lists... - $this->Lexer->addEntryPattern('\n (?![\*\-])',$mode,'preformatted'); - $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted'); - - // How to effect a sub pattern with the Lexer! - $this->Lexer->addPattern('\n ','preformatted'); - $this->Lexer->addPattern('\n\t','preformatted'); - - } - - function postConnect() { - $this->Lexer->addExitPattern('\n','preformatted'); - } - - function getSort() { - return 20; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_code extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addEntryPattern('<code\b(?=.*</code>)',$mode,'code'); - } - - function postConnect() { - $this->Lexer->addExitPattern('</code>','code'); - } - - function getSort() { - return 200; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_file extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addEntryPattern('<file\b(?=.*</file>)',$mode,'file'); - } - - function postConnect() { - $this->Lexer->addExitPattern('</file>','file'); - } - - function getSort() { - return 210; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_quote extends Doku_Parser_Mode { - - function __construct() { - global $PARSER_MODES; - - $this->allowedModes = array_merge ( - $PARSER_MODES['formatting'], - $PARSER_MODES['substition'], - $PARSER_MODES['disabled'], - $PARSER_MODES['protected'] #XXX new - ); - #$this->allowedModes[] = 'footnote'; - #$this->allowedModes[] = 'preformatted'; - #$this->allowedModes[] = 'unformatted'; - } - - function connectTo($mode) { - $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote'); - } - - function postConnect() { - $this->Lexer->addPattern('\n>{1,}','quote'); - $this->Lexer->addExitPattern('\n','quote'); - } - - function getSort() { - return 220; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_acronym extends Doku_Parser_Mode { - // A list - var $acronyms = array(); - var $pattern = ''; - - function __construct($acronyms) { - usort($acronyms,array($this,'_compare')); - $this->acronyms = $acronyms; - } - - function preConnect() { - if(!count($this->acronyms)) return; - - $bound = '[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]'; - $acronyms = array_map('Doku_Lexer_Escape',$this->acronyms); - $this->pattern = '(?<=^|'.$bound.')(?:'.join('|',$acronyms).')(?='.$bound.')'; - } - - function connectTo($mode) { - if(!count($this->acronyms)) return; - - if ( strlen($this->pattern) > 0 ) { - $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym'); - } - } - - function getSort() { - return 240; - } - - /** - * sort callback to order by string length descending - * - * @param string $a - * @param string $b - * - * @return int - */ - function _compare($a,$b) { - $a_len = strlen($a); - $b_len = strlen($b); - if ($a_len > $b_len) { - return -1; - } else if ($a_len < $b_len) { - return 1; - } - - return 0; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_smiley extends Doku_Parser_Mode { - // A list - var $smileys = array(); - var $pattern = ''; - - function __construct($smileys) { - $this->smileys = $smileys; - } - - function preConnect() { - if(!count($this->smileys) || $this->pattern != '') return; - - $sep = ''; - foreach ( $this->smileys as $smiley ) { - $this->pattern .= $sep.'(?<=\W|^)'.Doku_Lexer_Escape($smiley).'(?=\W|$)'; - $sep = '|'; - } - } - - function connectTo($mode) { - if(!count($this->smileys)) return; - - if ( strlen($this->pattern) > 0 ) { - $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley'); - } - } - - function getSort() { - return 230; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_wordblock extends Doku_Parser_Mode { - // A list - var $badwords = array(); - var $pattern = ''; - - function __construct($badwords) { - $this->badwords = $badwords; - } - - function preConnect() { - - if ( count($this->badwords) == 0 || $this->pattern != '') { - return; - } - - $sep = ''; - foreach ( $this->badwords as $badword ) { - $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)'; - $sep = '|'; - } - - } - - function connectTo($mode) { - if ( strlen($this->pattern) > 0 ) { - $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock'); - } - } - - function getSort() { - return 250; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_entity extends Doku_Parser_Mode { - // A list - var $entities = array(); - var $pattern = ''; - - function __construct($entities) { - $this->entities = $entities; - } - - function preConnect() { - if(!count($this->entities) || $this->pattern != '') return; - - $sep = ''; - foreach ( $this->entities as $entity ) { - $this->pattern .= $sep.Doku_Lexer_Escape($entity); - $sep = '|'; - } - } - - function connectTo($mode) { - if(!count($this->entities)) return; - - if ( strlen($this->pattern) > 0 ) { - $this->Lexer->addSpecialPattern($this->pattern,$mode,'entity'); - } - } - - function getSort() { - return 260; - } -} - -//------------------------------------------------------------------- -// Implements the 640x480 replacement -class Doku_Parser_Mode_multiplyentity extends Doku_Parser_Mode { - - function connectTo($mode) { - - $this->Lexer->addSpecialPattern( - '(?<=\b)(?:[1-9]|\d{2,})[xX]\d+(?=\b)',$mode,'multiplyentity' - ); - - } - - function getSort() { - return 270; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_quotes extends Doku_Parser_Mode { - - function connectTo($mode) { - global $conf; - - $ws = '\s/\#~:+=&%@\-\x28\x29\]\[{}><"\''; // whitespace - $punc = ';,\.?!'; - - if($conf['typography'] == 2){ - $this->Lexer->addSpecialPattern( - "(?<=^|[$ws])'(?=[^$ws$punc])",$mode,'singlequoteopening' - ); - $this->Lexer->addSpecialPattern( - "(?<=^|[^$ws]|[$punc])'(?=$|[$ws$punc])",$mode,'singlequoteclosing' - ); - $this->Lexer->addSpecialPattern( - "(?<=^|[^$ws$punc])'(?=$|[^$ws$punc])",$mode,'apostrophe' - ); - } - - $this->Lexer->addSpecialPattern( - "(?<=^|[$ws])\"(?=[^$ws$punc])",$mode,'doublequoteopening' - ); - $this->Lexer->addSpecialPattern( - "\"",$mode,'doublequoteclosing' - ); - - } - - function getSort() { - return 280; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_camelcaselink extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addSpecialPattern( - '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink' - ); - } - - function getSort() { - return 290; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_internallink extends Doku_Parser_Mode { - - function connectTo($mode) { - // Word boundaries? - $this->Lexer->addSpecialPattern("\[\[.*?\]\](?!\])",$mode,'internallink'); - } - - function getSort() { - return 300; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_media extends Doku_Parser_Mode { - - function connectTo($mode) { - // Word boundaries? - $this->Lexer->addSpecialPattern("\{\{(?:[^\}]|(?:\}[^\}]))+\}\}",$mode,'media'); - } - - function getSort() { - return 320; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_rss extends Doku_Parser_Mode { - - function connectTo($mode) { - $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss'); - } - - function getSort() { - return 310; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_externallink extends Doku_Parser_Mode { - var $schemes = array(); - var $patterns = array(); - - function preConnect() { - if(count($this->patterns)) return; - - $ltrs = '\w'; - $gunk = '/\#~:.?+=&%@!\-\[\]'; - $punc = '.:?\-;,'; - $host = $ltrs.$punc; - $any = $ltrs.$gunk.$punc; - - $this->schemes = getSchemes(); - foreach ( $this->schemes as $scheme ) { - $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; - } - - $this->patterns[] = '(?<=\s)(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; - $this->patterns[] = '(?<=\s)(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; - } - - function connectTo($mode) { - - foreach ( $this->patterns as $pattern ) { - $this->Lexer->addSpecialPattern($pattern,$mode,'externallink'); - } - } - - function getSort() { - return 330; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_filelink extends Doku_Parser_Mode { - - var $pattern; - - function preConnect() { - - $ltrs = '\w'; - $gunk = '/\#~:.?+=&%@!\-'; - $punc = '.:?\-;,'; - $host = $ltrs.$punc; - $any = $ltrs.$gunk.$punc; - - $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['. - $punc.']*[^'.$any.']'; - } - - function connectTo($mode) { - $this->Lexer->addSpecialPattern( - $this->pattern,$mode,'filelink'); - } - - function getSort() { - return 360; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_windowssharelink extends Doku_Parser_Mode { - - var $pattern; - - function preConnect() { - $this->pattern = "\\\\\\\\\w+?(?:\\\\[\w\-$]+)+"; - } - - function connectTo($mode) { - $this->Lexer->addSpecialPattern( - $this->pattern,$mode,'windowssharelink'); - } - - function getSort() { - return 350; - } -} - -//------------------------------------------------------------------- -class Doku_Parser_Mode_emaillink extends Doku_Parser_Mode { - - function connectTo($mode) { - // pattern below is defined in inc/mail.php - $this->Lexer->addSpecialPattern('<'.PREG_PATTERN_VALID_EMAIL.'>',$mode,'emaillink'); - } - - function getSort() { - return 340; - } -} - - -//Setup VIM: ex: et ts=4 : diff --git a/wiki/inc/parser/renderer.php b/wiki/inc/parser/renderer.php deleted file mode 100644 index 83b51d4..0000000 --- a/wiki/inc/parser/renderer.php +++ /dev/null @@ -1,883 +0,0 @@ -<?php -/** - * Renderer output base class - * - * @author Harry Fuecks <hfuecks@gmail.com> - * @author Andreas Gohr <andi@splitbrain.org> - */ -if(!defined('DOKU_INC')) die('meh.'); - -/** - * Allowed chars in $language for code highlighting - * @see GeSHi::set_language() - */ -define('PREG_PATTERN_VALID_LANGUAGE', '#[^a-zA-Z0-9\-_]#'); - -/** - * An empty renderer, produces no output - * - * Inherits from DokuWiki_Plugin for giving additional functions to render plugins - * - * The renderer transforms the syntax instructions created by the parser and handler into the - * desired output format. For each instruction a corresponding method defined in this class will - * be called. That method needs to produce the desired output for the instruction and add it to the - * $doc field. When all instructions are processed, the $doc field contents will be cached by - * DokuWiki and sent to the user. - */ -class Doku_Renderer extends DokuWiki_Plugin { - /** @var array Settings, control the behavior of the renderer */ - public $info = array( - 'cache' => true, // may the rendered result cached? - 'toc' => true, // render the TOC? - ); - - /** @var array contains the smiley configuration, set in p_render() */ - public $smileys = array(); - /** @var array contains the entity configuration, set in p_render() */ - public $entities = array(); - /** @var array contains the acronym configuration, set in p_render() */ - public $acronyms = array(); - /** @var array contains the interwiki configuration, set in p_render() */ - public $interwiki = array(); - - /** - * @var string the rendered document, this will be cached after the renderer ran through - */ - public $doc = ''; - - /** - * clean out any per-use values - * - * This is called before each use of the renderer object and should be used to - * completely reset the state of the renderer to be reused for a new document - */ - function reset() { - } - - /** - * Allow the plugin to prevent DokuWiki from reusing an instance - * - * Since most renderer plugins fail to implement Doku_Renderer::reset() we default - * to reinstantiating the renderer here - * - * @return bool false if the plugin has to be instantiated - */ - function isSingleton() { - return false; - } - - /** - * Returns the format produced by this renderer. - * - * Has to be overidden by sub classes - * - * @return string - */ - function getFormat() { - trigger_error('getFormat() not implemented in '.get_class($this), E_USER_WARNING); - return ''; - } - - /** - * Disable caching of this renderer's output - */ - function nocache() { - $this->info['cache'] = false; - } - - /** - * Disable TOC generation for this renderer's output - * - * This might not be used for certain sub renderer - */ - function notoc() { - $this->info['toc'] = false; - } - - /** - * Handle plugin rendering - * - * Most likely this needs NOT to be overwritten by sub classes - * - * @param string $name Plugin name - * @param mixed $data custom data set by handler - * @param string $state matched state if any - * @param string $match raw matched syntax - */ - function plugin($name, $data, $state = '', $match = '') { - /** @var DokuWiki_Syntax_Plugin $plugin */ - $plugin = plugin_load('syntax', $name); - if($plugin != null) { - $plugin->render($this->getFormat(), $this, $data); - } - } - - /** - * handle nested render instructions - * this method (and nest_close method) should not be overloaded in actual renderer output classes - * - * @param array $instructions - */ - function nest($instructions) { - foreach($instructions as $instruction) { - // execute the callback against ourself - if(method_exists($this, $instruction[0])) { - call_user_func_array(array($this, $instruction[0]), $instruction[1] ? $instruction[1] : array()); - } - } - } - - /** - * dummy closing instruction issued by Doku_Handler_Nest - * - * normally the syntax mode should override this instruction when instantiating Doku_Handler_Nest - - * however plugins will not be able to - as their instructions require data. - */ - function nest_close() { - } - - #region Syntax modes - sub classes will need to implement them to fill $doc - - /** - * Initialize the document - */ - function document_start() { - } - - /** - * Finalize the document - */ - function document_end() { - } - - /** - * Render the Table of Contents - * - * @return string - */ - function render_TOC() { - return ''; - } - - /** - * Add an item to the TOC - * - * @param string $id the hash link - * @param string $text the text to display - * @param int $level the nesting level - */ - function toc_additem($id, $text, $level) { - } - - /** - * Render a heading - * - * @param string $text the text to display - * @param int $level header level - * @param int $pos byte position in the original source - */ - function header($text, $level, $pos) { - } - - /** - * Open a new section - * - * @param int $level section level (as determined by the previous header) - */ - function section_open($level) { - } - - /** - * Close the current section - */ - function section_close() { - } - - /** - * Render plain text data - * - * @param string $text - */ - function cdata($text) { - } - - /** - * Open a paragraph - */ - function p_open() { - } - - /** - * Close a paragraph - */ - function p_close() { - } - - /** - * Create a line break - */ - function linebreak() { - } - - /** - * Create a horizontal line - */ - function hr() { - } - - /** - * Start strong (bold) formatting - */ - function strong_open() { - } - - /** - * Stop strong (bold) formatting - */ - function strong_close() { - } - - /** - * Start emphasis (italics) formatting - */ - function emphasis_open() { - } - - /** - * Stop emphasis (italics) formatting - */ - function emphasis_close() { - } - - /** - * Start underline formatting - */ - function underline_open() { - } - - /** - * Stop underline formatting - */ - function underline_close() { - } - - /** - * Start monospace formatting - */ - function monospace_open() { - } - - /** - * Stop monospace formatting - */ - function monospace_close() { - } - - /** - * Start a subscript - */ - function subscript_open() { - } - - /** - * Stop a subscript - */ - function subscript_close() { - } - - /** - * Start a superscript - */ - function superscript_open() { - } - - /** - * Stop a superscript - */ - function superscript_close() { - } - - /** - * Start deleted (strike-through) formatting - */ - function deleted_open() { - } - - /** - * Stop deleted (strike-through) formatting - */ - function deleted_close() { - } - - /** - * Start a footnote - */ - function footnote_open() { - } - - /** - * Stop a footnote - */ - function footnote_close() { - } - - /** - * Open an unordered list - */ - function listu_open() { - } - - /** - * Close an unordered list - */ - function listu_close() { - } - - /** - * Open an ordered list - */ - function listo_open() { - } - - /** - * Close an ordered list - */ - function listo_close() { - } - - /** - * Open a list item - * - * @param int $level the nesting level - * @param bool $node true when a node; false when a leaf - */ - function listitem_open($level,$node=false) { - } - - /** - * Close a list item - */ - function listitem_close() { - } - - /** - * Start the content of a list item - */ - function listcontent_open() { - } - - /** - * Stop the content of a list item - */ - function listcontent_close() { - } - - /** - * Output unformatted $text - * - * Defaults to $this->cdata() - * - * @param string $text - */ - function unformatted($text) { - $this->cdata($text); - } - - /** - * Output inline PHP code - * - * If $conf['phpok'] is true this should evaluate the given code and append the result - * to $doc - * - * @param string $text The PHP code - */ - function php($text) { - } - - /** - * Output block level PHP code - * - * If $conf['phpok'] is true this should evaluate the given code and append the result - * to $doc - * - * @param string $text The PHP code - */ - function phpblock($text) { - } - - /** - * Output raw inline HTML - * - * If $conf['htmlok'] is true this should add the code as is to $doc - * - * @param string $text The HTML - */ - function html($text) { - } - - /** - * Output raw block-level HTML - * - * If $conf['htmlok'] is true this should add the code as is to $doc - * - * @param string $text The HTML - */ - function htmlblock($text) { - } - - /** - * Output preformatted text - * - * @param string $text - */ - function preformatted($text) { - } - - /** - * Start a block quote - */ - function quote_open() { - } - - /** - * Stop a block quote - */ - function quote_close() { - } - - /** - * Display text as file content, optionally syntax highlighted - * - * @param string $text text to show - * @param string $lang programming language to use for syntax highlighting - * @param string $file file path label - */ - function file($text, $lang = null, $file = null) { - } - - /** - * Display text as code content, optionally syntax highlighted - * - * @param string $text text to show - * @param string $lang programming language to use for syntax highlighting - * @param string $file file path label - */ - function code($text, $lang = null, $file = null) { - } - - /** - * Format an acronym - * - * Uses $this->acronyms - * - * @param string $acronym - */ - function acronym($acronym) { - } - - /** - * Format a smiley - * - * Uses $this->smiley - * - * @param string $smiley - */ - function smiley($smiley) { - } - - /** - * Format an entity - * - * Entities are basically small text replacements - * - * Uses $this->entities - * - * @param string $entity - */ - function entity($entity) { - } - - /** - * Typographically format a multiply sign - * - * Example: ($x=640, $y=480) should result in "640×480" - * - * @param string|int $x first value - * @param string|int $y second value - */ - function multiplyentity($x, $y) { - } - - /** - * Render an opening single quote char (language specific) - */ - function singlequoteopening() { - } - - /** - * Render a closing single quote char (language specific) - */ - function singlequoteclosing() { - } - - /** - * Render an apostrophe char (language specific) - */ - function apostrophe() { - } - - /** - * Render an opening double quote char (language specific) - */ - function doublequoteopening() { - } - - /** - * Render an closinging double quote char (language specific) - */ - function doublequoteclosing() { - } - - /** - * Render a CamelCase link - * - * @param string $link The link name - * @see http://en.wikipedia.org/wiki/CamelCase - */ - function camelcaselink($link) { - } - - /** - * Render a page local link - * - * @param string $hash hash link identifier - * @param string $name name for the link - */ - function locallink($hash, $name = null) { - } - - /** - * Render a wiki internal link - * - * @param string $link page ID to link to. eg. 'wiki:syntax' - * @param string|array $title name for the link, array for media file - */ - function internallink($link, $title = null) { - } - - /** - * Render an external link - * - * @param string $link full URL with scheme - * @param string|array $title name for the link, array for media file - */ - function externallink($link, $title = null) { - } - - /** - * Render the output of an RSS feed - * - * @param string $url URL of the feed - * @param array $params Finetuning of the output - */ - function rss($url, $params) { - } - - /** - * Render an interwiki link - * - * You may want to use $this->_resolveInterWiki() here - * - * @param string $link original link - probably not much use - * @param string|array $title name for the link, array for media file - * @param string $wikiName indentifier (shortcut) for the remote wiki - * @param string $wikiUri the fragment parsed from the original link - */ - function interwikilink($link, $title = null, $wikiName, $wikiUri) { - } - - /** - * Link to file on users OS - * - * @param string $link the link - * @param string|array $title name for the link, array for media file - */ - function filelink($link, $title = null) { - } - - /** - * Link to windows share - * - * @param string $link the link - * @param string|array $title name for the link, array for media file - */ - function windowssharelink($link, $title = null) { - } - - /** - * Render a linked E-Mail Address - * - * Should honor $conf['mailguard'] setting - * - * @param string $address Email-Address - * @param string|array $name name for the link, array for media file - */ - function emaillink($address, $name = null) { - } - - /** - * Render an internal media file - * - * @param string $src media ID - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - * @param string $linking linkonly|detail|nolink - */ - function internalmedia($src, $title = null, $align = null, $width = null, - $height = null, $cache = null, $linking = null) { - } - - /** - * Render an external media file - * - * @param string $src full media URL - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - * @param string $linking linkonly|detail|nolink - */ - function externalmedia($src, $title = null, $align = null, $width = null, - $height = null, $cache = null, $linking = null) { - } - - /** - * Render a link to an internal media file - * - * @param string $src media ID - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - */ - function internalmedialink($src, $title = null, $align = null, - $width = null, $height = null, $cache = null) { - } - - /** - * Render a link to an external media file - * - * @param string $src media ID - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - */ - function externalmedialink($src, $title = null, $align = null, - $width = null, $height = null, $cache = null) { - } - - /** - * Start a table - * - * @param int $maxcols maximum number of columns - * @param int $numrows NOT IMPLEMENTED - * @param int $pos byte position in the original source - */ - function table_open($maxcols = null, $numrows = null, $pos = null) { - } - - /** - * Close a table - * - * @param int $pos byte position in the original source - */ - function table_close($pos = null) { - } - - /** - * Open a table header - */ - function tablethead_open() { - } - - /** - * Close a table header - */ - function tablethead_close() { - } - - /** - * Open a table body - */ - function tabletbody_open() { - } - - /** - * Close a table body - */ - function tabletbody_close() { - } - - /** - * Open a table footer - */ - function tabletfoot_open() { - } - - /** - * Close a table footer - */ - function tabletfoot_close() { - } - - /** - * Open a table row - */ - function tablerow_open() { - } - - /** - * Close a table row - */ - function tablerow_close() { - } - - /** - * Open a table header cell - * - * @param int $colspan - * @param string $align left|center|right - * @param int $rowspan - */ - function tableheader_open($colspan = 1, $align = null, $rowspan = 1) { - } - - /** - * Close a table header cell - */ - function tableheader_close() { - } - - /** - * Open a table cell - * - * @param int $colspan - * @param string $align left|center|right - * @param int $rowspan - */ - function tablecell_open($colspan = 1, $align = null, $rowspan = 1) { - } - - /** - * Close a table cell - */ - function tablecell_close() { - } - - #endregion - - #region util functions, you probably won't need to reimplement them - - /** - * Removes any Namespace from the given name but keeps - * casing and special chars - * - * @author Andreas Gohr <andi@splitbrain.org> - * - * @param string $name - * @return string - */ - function _simpleTitle($name) { - global $conf; - - //if there is a hash we use the ancor name only - @list($name, $hash) = explode('#', $name, 2); - if($hash) return $hash; - - if($conf['useslash']) { - $name = strtr($name, ';/', ';:'); - } else { - $name = strtr($name, ';', ':'); - } - - return noNSorNS($name); - } - - /** - * Resolve an interwikilink - * - * @param string $shortcut identifier for the interwiki link - * @param string $reference fragment that refers the content - * @param null|bool $exists reference which returns if an internal page exists - * @return string interwikilink - */ - function _resolveInterWiki(&$shortcut, $reference, &$exists = null) { - //get interwiki URL - if(isset($this->interwiki[$shortcut])) { - $url = $this->interwiki[$shortcut]; - } else { - // Default to Google I'm feeling lucky - $url = 'https://www.google.com/search?q={URL}&btnI=lucky'; - $shortcut = 'go'; - } - - //split into hash and url part - $hash = strrchr($reference, '#'); - if($hash) { - $reference = substr($reference, 0, -strlen($hash)); - $hash = substr($hash, 1); - } - - //replace placeholder - if(preg_match('#\{(URL|NAME|SCHEME|HOST|PORT|PATH|QUERY)\}#', $url)) { - //use placeholders - $url = str_replace('{URL}', rawurlencode($reference), $url); - //wiki names will be cleaned next, otherwise urlencode unsafe chars - $url = str_replace('{NAME}', ($url{0} === ':') ? $reference : - preg_replace_callback('/[[\\\\\]^`{|}#%]/', function($match) { - return rawurlencode($match[0]); - }, $reference), $url); - $parsed = parse_url($reference); - if (empty($parsed['scheme'])) $parsed['scheme'] = ''; - if (empty($parsed['host'])) $parsed['host'] = ''; - if (empty($parsed['port'])) $parsed['port'] = 80; - if (empty($parsed['path'])) $parsed['path'] = ''; - if (empty($parsed['query'])) $parsed['query'] = ''; - $url = strtr($url,[ - '{SCHEME}' => $parsed['scheme'], - '{HOST}' => $parsed['host'], - '{PORT}' => $parsed['port'], - '{PATH}' => $parsed['path'], - '{QUERY}' => $parsed['query'] , - ]); - } else { - //default - $url = $url.rawurlencode($reference); - } - //handle as wiki links - if($url{0} === ':') { - $urlparam = null; - $id = $url; - if (strpos($url, '?') !== false) { - list($id, $urlparam) = explode('?', $url, 2); - } - $url = wl(cleanID($id), $urlparam); - $exists = page_exists($id); - } - if($hash) $url .= '#'.rawurlencode($hash); - - return $url; - } - - #endregion -} - - -//Setup VIM: ex: et ts=4 : diff --git a/wiki/inc/parser/xhtml.php b/wiki/inc/parser/xhtml.php deleted file mode 100644 index a3e7b45..0000000 --- a/wiki/inc/parser/xhtml.php +++ /dev/null @@ -1,1970 +0,0 @@ -<?php -/** - * Renderer for XHTML output - * - * @author Harry Fuecks <hfuecks@gmail.com> - * @author Andreas Gohr <andi@splitbrain.org> - */ -if(!defined('DOKU_INC')) die('meh.'); - -if(!defined('DOKU_LF')) { - // Some whitespace to help View > Source - define ('DOKU_LF', "\n"); -} - -if(!defined('DOKU_TAB')) { - // Some whitespace to help View > Source - define ('DOKU_TAB', "\t"); -} - -/** - * The XHTML Renderer - * - * This is DokuWiki's main renderer used to display page content in the wiki - */ -class Doku_Renderer_xhtml extends Doku_Renderer { - /** @var array store the table of contents */ - public $toc = array(); - - /** @var array A stack of section edit data */ - protected $sectionedits = array(); - var $date_at = ''; // link pages and media against this revision - - /** @var int last section edit id, used by startSectionEdit */ - protected $lastsecid = 0; - - /** @var array the list of headers used to create unique link ids */ - protected $headers = array(); - - /** @var array a list of footnotes, list starts at 1! */ - protected $footnotes = array(); - - /** @var int current section level */ - protected $lastlevel = 0; - /** @var array section node tracker */ - protected $node = array(0, 0, 0, 0, 0); - - /** @var string temporary $doc store */ - protected $store = ''; - - /** @var array global counter, for table classes etc. */ - protected $_counter = array(); // - - /** @var int counts the code and file blocks, used to provide download links */ - protected $_codeblock = 0; - - /** @var array list of allowed URL schemes */ - protected $schemes = null; - - /** - * Register a new edit section range - * - * @param int $start The byte position for the edit start - * @param array $data Associative array with section data: - * Key 'name': the section name/title - * Key 'target': the target for the section edit, - * e.g. 'section' or 'table' - * Key 'hid': header id - * Key 'codeblockOffset': actual code block index - * Key 'start': set in startSectionEdit(), - * do not set yourself - * Key 'range': calculated from 'start' and - * $key in finishSectionEdit(), - * do not set yourself - * @return string A marker class for the starting HTML element - * - * @author Adrian Lang <lang@cosmocode.de> - */ - public function startSectionEdit($start, $data) { - if (!is_array($data)) { - msg( - sprintf( - 'startSectionEdit: $data "%s" is NOT an array! One of your plugins needs an update.', - hsc((string) $data) - ), -1 - ); - - // @deprecated 2018-04-14, backward compatibility - $args = func_get_args(); - $data = array(); - if(isset($args[1])) $data['target'] = $args[1]; - if(isset($args[2])) $data['name'] = $args[2]; - if(isset($args[3])) $data['hid'] = $args[3]; - } - $data['secid'] = ++$this->lastsecid; - $data['start'] = $start; - $this->sectionedits[] = $data; - return 'sectionedit'.$data['secid']; - } - - /** - * Finish an edit section range - * - * @param int $end The byte position for the edit end; null for the rest of the page - * - * @author Adrian Lang <lang@cosmocode.de> - */ - public function finishSectionEdit($end = null, $hid = null) { - $data = array_pop($this->sectionedits); - if(!is_null($end) && $end <= $data['start']) { - return; - } - if(!is_null($hid)) { - $data['hid'] .= $hid; - } - $data['range'] = $data['start'].'-'.(is_null($end) ? '' : $end); - unset($data['start']); - $this->doc .= '<!-- EDIT'.hsc(json_encode ($data)).' -->'; - } - - /** - * Returns the format produced by this renderer. - * - * @return string always 'xhtml' - */ - function getFormat() { - return 'xhtml'; - } - - /** - * Initialize the document - */ - function document_start() { - //reset some internals - $this->toc = array(); - $this->headers = array(); - } - - /** - * Finalize the document - */ - function document_end() { - // Finish open section edits. - while(count($this->sectionedits) > 0) { - if($this->sectionedits[count($this->sectionedits) - 1]['start'] <= 1) { - // If there is only one section, do not write a section edit - // marker. - array_pop($this->sectionedits); - } else { - $this->finishSectionEdit(); - } - } - - if(count($this->footnotes) > 0) { - $this->doc .= '<div class="footnotes">'.DOKU_LF; - - foreach($this->footnotes as $id => $footnote) { - // check its not a placeholder that indicates actual footnote text is elsewhere - if(substr($footnote, 0, 5) != "@@FNT") { - - // open the footnote and set the anchor and backlink - $this->doc .= '<div class="fn">'; - $this->doc .= '<sup><a href="#fnt__'.$id.'" id="fn__'.$id.'" class="fn_bot">'; - $this->doc .= $id.')</a></sup> '.DOKU_LF; - - // get any other footnotes that use the same markup - $alt = array_keys($this->footnotes, "@@FNT$id"); - - if(count($alt)) { - foreach($alt as $ref) { - // set anchor and backlink for the other footnotes - $this->doc .= ', <sup><a href="#fnt__'.($ref).'" id="fn__'.($ref).'" class="fn_bot">'; - $this->doc .= ($ref).')</a></sup> '.DOKU_LF; - } - } - - // add footnote markup and close this footnote - $this->doc .= '<div class="content">'.$footnote.'</div>'; - $this->doc .= '</div>'.DOKU_LF; - } - } - $this->doc .= '</div>'.DOKU_LF; - } - - // Prepare the TOC - global $conf; - if($this->info['toc'] && is_array($this->toc) && $conf['tocminheads'] && count($this->toc) >= $conf['tocminheads']) { - global $TOC; - $TOC = $this->toc; - } - - // make sure there are no empty paragraphs - $this->doc = preg_replace('#<p>\s*</p>#', '', $this->doc); - } - - /** - * Add an item to the TOC - * - * @param string $id the hash link - * @param string $text the text to display - * @param int $level the nesting level - */ - function toc_additem($id, $text, $level) { - global $conf; - - //handle TOC - if($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']) { - $this->toc[] = html_mktocitem($id, $text, $level - $conf['toptoclevel'] + 1); - } - } - - /** - * Render a heading - * - * @param string $text the text to display - * @param int $level header level - * @param int $pos byte position in the original source - */ - function header($text, $level, $pos) { - global $conf; - - if(blank($text)) return; //skip empty headlines - - $hid = $this->_headerToLink($text, true); - - //only add items within configured levels - $this->toc_additem($hid, $text, $level); - - // adjust $node to reflect hierarchy of levels - $this->node[$level - 1]++; - if($level < $this->lastlevel) { - for($i = 0; $i < $this->lastlevel - $level; $i++) { - $this->node[$this->lastlevel - $i - 1] = 0; - } - } - $this->lastlevel = $level; - - if($level <= $conf['maxseclevel'] && - count($this->sectionedits) > 0 && - $this->sectionedits[count($this->sectionedits) - 1]['target'] === 'section' - ) { - $this->finishSectionEdit($pos - 1); - } - - // write the header - $this->doc .= DOKU_LF.'<h'.$level; - if($level <= $conf['maxseclevel']) { - $data = array(); - $data['target'] = 'section'; - $data['name'] = $text; - $data['hid'] = $hid; - $data['codeblockOffset'] = $this->_codeblock; - $this->doc .= ' class="'.$this->startSectionEdit($pos, $data).'"'; - } - $this->doc .= ' id="'.$hid.'">'; - $this->doc .= $this->_xmlEntities($text); - $this->doc .= "</h$level>".DOKU_LF; - } - - /** - * Open a new section - * - * @param int $level section level (as determined by the previous header) - */ - function section_open($level) { - $this->doc .= '<div class="level'.$level.'">'.DOKU_LF; - } - - /** - * Close the current section - */ - function section_close() { - $this->doc .= DOKU_LF.'</div>'.DOKU_LF; - } - - /** - * Render plain text data - * - * @param $text - */ - function cdata($text) { - $this->doc .= $this->_xmlEntities($text); - } - - /** - * Open a paragraph - */ - function p_open() { - $this->doc .= DOKU_LF.'<p>'.DOKU_LF; - } - - /** - * Close a paragraph - */ - function p_close() { - $this->doc .= DOKU_LF.'</p>'.DOKU_LF; - } - - /** - * Create a line break - */ - function linebreak() { - $this->doc .= '<br/>'.DOKU_LF; - } - - /** - * Create a horizontal line - */ - function hr() { - $this->doc .= '<hr />'.DOKU_LF; - } - - /** - * Start strong (bold) formatting - */ - function strong_open() { - $this->doc .= '<strong>'; - } - - /** - * Stop strong (bold) formatting - */ - function strong_close() { - $this->doc .= '</strong>'; - } - - /** - * Start emphasis (italics) formatting - */ - function emphasis_open() { - $this->doc .= '<em>'; - } - - /** - * Stop emphasis (italics) formatting - */ - function emphasis_close() { - $this->doc .= '</em>'; - } - - /** - * Start underline formatting - */ - function underline_open() { - $this->doc .= '<em class="u">'; - } - - /** - * Stop underline formatting - */ - function underline_close() { - $this->doc .= '</em>'; - } - - /** - * Start monospace formatting - */ - function monospace_open() { - $this->doc .= '<code>'; - } - - /** - * Stop monospace formatting - */ - function monospace_close() { - $this->doc .= '</code>'; - } - - /** - * Start a subscript - */ - function subscript_open() { - $this->doc .= '<sub>'; - } - - /** - * Stop a subscript - */ - function subscript_close() { - $this->doc .= '</sub>'; - } - - /** - * Start a superscript - */ - function superscript_open() { - $this->doc .= '<sup>'; - } - - /** - * Stop a superscript - */ - function superscript_close() { - $this->doc .= '</sup>'; - } - - /** - * Start deleted (strike-through) formatting - */ - function deleted_open() { - $this->doc .= '<del>'; - } - - /** - * Stop deleted (strike-through) formatting - */ - function deleted_close() { - $this->doc .= '</del>'; - } - - /** - * Callback for footnote start syntax - * - * All following content will go to the footnote instead of - * the document. To achieve this the previous rendered content - * is moved to $store and $doc is cleared - * - * @author Andreas Gohr <andi@splitbrain.org> - */ - function footnote_open() { - - // move current content to store and record footnote - $this->store = $this->doc; - $this->doc = ''; - } - - /** - * Callback for footnote end syntax - * - * All rendered content is moved to the $footnotes array and the old - * content is restored from $store again - * - * @author Andreas Gohr - */ - function footnote_close() { - /** @var $fnid int takes track of seen footnotes, assures they are unique even across multiple docs FS#2841 */ - static $fnid = 0; - // assign new footnote id (we start at 1) - $fnid++; - - // recover footnote into the stack and restore old content - $footnote = $this->doc; - $this->doc = $this->store; - $this->store = ''; - - // check to see if this footnote has been seen before - $i = array_search($footnote, $this->footnotes); - - if($i === false) { - // its a new footnote, add it to the $footnotes array - $this->footnotes[$fnid] = $footnote; - } else { - // seen this one before, save a placeholder - $this->footnotes[$fnid] = "@@FNT".($i); - } - - // output the footnote reference and link - $this->doc .= '<sup><a href="#fn__'.$fnid.'" id="fnt__'.$fnid.'" class="fn_top">'.$fnid.')</a></sup>'; - } - - /** - * Open an unordered list - * - * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input - */ - function listu_open($classes = null) { - $class = ''; - if($classes !== null) { - if(is_array($classes)) $classes = join(' ', $classes); - $class = " class=\"$classes\""; - } - $this->doc .= "<ul$class>".DOKU_LF; - } - - /** - * Close an unordered list - */ - function listu_close() { - $this->doc .= '</ul>'.DOKU_LF; - } - - /** - * Open an ordered list - * - * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input - */ - function listo_open($classes = null) { - $class = ''; - if($classes !== null) { - if(is_array($classes)) $classes = join(' ', $classes); - $class = " class=\"$classes\""; - } - $this->doc .= "<ol$class>".DOKU_LF; - } - - /** - * Close an ordered list - */ - function listo_close() { - $this->doc .= '</ol>'.DOKU_LF; - } - - /** - * Open a list item - * - * @param int $level the nesting level - * @param bool $node true when a node; false when a leaf - */ - function listitem_open($level, $node=false) { - $branching = $node ? ' node' : ''; - $this->doc .= '<li class="level'.$level.$branching.'">'; - } - - /** - * Close a list item - */ - function listitem_close() { - $this->doc .= '</li>'.DOKU_LF; - } - - /** - * Start the content of a list item - */ - function listcontent_open() { - $this->doc .= '<div class="li">'; - } - - /** - * Stop the content of a list item - */ - function listcontent_close() { - $this->doc .= '</div>'.DOKU_LF; - } - - /** - * Output unformatted $text - * - * Defaults to $this->cdata() - * - * @param string $text - */ - function unformatted($text) { - $this->doc .= $this->_xmlEntities($text); - } - - /** - * Execute PHP code if allowed - * - * @param string $text PHP code that is either executed or printed - * @param string $wrapper html element to wrap result if $conf['phpok'] is okff - * - * @author Andreas Gohr <andi@splitbrain.org> - */ - function php($text, $wrapper = 'code') { - global $conf; - - if($conf['phpok']) { - ob_start(); - eval($text); - $this->doc .= ob_get_contents(); - ob_end_clean(); - } else { - $this->doc .= p_xhtml_cached_geshi($text, 'php', $wrapper); - } - } - - /** - * Output block level PHP code - * - * If $conf['phpok'] is true this should evaluate the given code and append the result - * to $doc - * - * @param string $text The PHP code - */ - function phpblock($text) { - $this->php($text, 'pre'); - } - - /** - * Insert HTML if allowed - * - * @param string $text html text - * @param string $wrapper html element to wrap result if $conf['htmlok'] is okff - * - * @author Andreas Gohr <andi@splitbrain.org> - */ - function html($text, $wrapper = 'code') { - global $conf; - - if($conf['htmlok']) { - $this->doc .= $text; - } else { - $this->doc .= p_xhtml_cached_geshi($text, 'html4strict', $wrapper); - } - } - - /** - * Output raw block-level HTML - * - * If $conf['htmlok'] is true this should add the code as is to $doc - * - * @param string $text The HTML - */ - function htmlblock($text) { - $this->html($text, 'pre'); - } - - /** - * Start a block quote - */ - function quote_open() { - $this->doc .= '<blockquote><div class="no">'.DOKU_LF; - } - - /** - * Stop a block quote - */ - function quote_close() { - $this->doc .= '</div></blockquote>'.DOKU_LF; - } - - /** - * Output preformatted text - * - * @param string $text - */ - function preformatted($text) { - $this->doc .= '<pre class="code">'.trim($this->_xmlEntities($text), "\n\r").'</pre>'.DOKU_LF; - } - - /** - * Display text as file content, optionally syntax highlighted - * - * @param string $text text to show - * @param string $language programming language to use for syntax highlighting - * @param string $filename file path label - * @param array $options assoziative array with additional geshi options - */ - function file($text, $language = null, $filename = null, $options=null) { - $this->_highlight('file', $text, $language, $filename, $options); - } - - /** - * Display text as code content, optionally syntax highlighted - * - * @param string $text text to show - * @param string $language programming language to use for syntax highlighting - * @param string $filename file path label - * @param array $options assoziative array with additional geshi options - */ - function code($text, $language = null, $filename = null, $options=null) { - $this->_highlight('code', $text, $language, $filename, $options); - } - - /** - * Use GeSHi to highlight language syntax in code and file blocks - * - * @author Andreas Gohr <andi@splitbrain.org> - * @param string $type code|file - * @param string $text text to show - * @param string $language programming language to use for syntax highlighting - * @param string $filename file path label - * @param array $options assoziative array with additional geshi options - */ - function _highlight($type, $text, $language = null, $filename = null, $options = null) { - global $ID; - global $lang; - global $INPUT; - - $language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language); - - $language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language); - - if($filename) { - // add icon - list($ext) = mimetype($filename, false); - $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext); - $class = 'mediafile mf_'.$class; - - $offset = 0; - if ($INPUT->has('codeblockOffset')) { - $offset = $INPUT->str('codeblockOffset'); - } - $this->doc .= '<dl class="'.$type.'">'.DOKU_LF; - $this->doc .= '<dt><a href="'.exportlink($ID, 'code', array('codeblock' => $offset+$this->_codeblock)).'" title="'.$lang['download'].'" class="'.$class.'">'; - $this->doc .= hsc($filename); - $this->doc .= '</a></dt>'.DOKU_LF.'<dd>'; - } - - if($text{0} == "\n") { - $text = substr($text, 1); - } - if(substr($text, -1) == "\n") { - $text = substr($text, 0, -1); - } - - if(empty($language)) { // empty is faster than is_null and can prevent '' string - $this->doc .= '<pre class="'.$type.'">'.$this->_xmlEntities($text).'</pre>'.DOKU_LF; - } else { - $class = 'code'; //we always need the code class to make the syntax highlighting apply - if($type != 'code') $class .= ' '.$type; - - $this->doc .= "<pre class=\"$class $language\">".p_xhtml_cached_geshi($text, $language, '', $options).'</pre>'.DOKU_LF; - } - - if($filename) { - $this->doc .= '</dd></dl>'.DOKU_LF; - } - - $this->_codeblock++; - } - - /** - * Format an acronym - * - * Uses $this->acronyms - * - * @param string $acronym - */ - function acronym($acronym) { - - if(array_key_exists($acronym, $this->acronyms)) { - - $title = $this->_xmlEntities($this->acronyms[$acronym]); - - $this->doc .= '<abbr title="'.$title - .'">'.$this->_xmlEntities($acronym).'</abbr>'; - - } else { - $this->doc .= $this->_xmlEntities($acronym); - } - } - - /** - * Format a smiley - * - * Uses $this->smiley - * - * @param string $smiley - */ - function smiley($smiley) { - if(array_key_exists($smiley, $this->smileys)) { - $this->doc .= '<img src="'.DOKU_BASE.'lib/images/smileys/'.$this->smileys[$smiley]. - '" class="icon" alt="'. - $this->_xmlEntities($smiley).'" />'; - } else { - $this->doc .= $this->_xmlEntities($smiley); - } - } - - /** - * Format an entity - * - * Entities are basically small text replacements - * - * Uses $this->entities - * - * @param string $entity - */ - function entity($entity) { - if(array_key_exists($entity, $this->entities)) { - $this->doc .= $this->entities[$entity]; - } else { - $this->doc .= $this->_xmlEntities($entity); - } - } - - /** - * Typographically format a multiply sign - * - * Example: ($x=640, $y=480) should result in "640×480" - * - * @param string|int $x first value - * @param string|int $y second value - */ - function multiplyentity($x, $y) { - $this->doc .= "$x×$y"; - } - - /** - * Render an opening single quote char (language specific) - */ - function singlequoteopening() { - global $lang; - $this->doc .= $lang['singlequoteopening']; - } - - /** - * Render a closing single quote char (language specific) - */ - function singlequoteclosing() { - global $lang; - $this->doc .= $lang['singlequoteclosing']; - } - - /** - * Render an apostrophe char (language specific) - */ - function apostrophe() { - global $lang; - $this->doc .= $lang['apostrophe']; - } - - /** - * Render an opening double quote char (language specific) - */ - function doublequoteopening() { - global $lang; - $this->doc .= $lang['doublequoteopening']; - } - - /** - * Render an closinging double quote char (language specific) - */ - function doublequoteclosing() { - global $lang; - $this->doc .= $lang['doublequoteclosing']; - } - - /** - * Render a CamelCase link - * - * @param string $link The link name - * @param bool $returnonly whether to return html or write to doc attribute - * @return void|string writes to doc attribute or returns html depends on $returnonly - * - * @see http://en.wikipedia.org/wiki/CamelCase - */ - function camelcaselink($link, $returnonly = false) { - if($returnonly) { - return $this->internallink($link, $link, null, true); - } else { - $this->internallink($link, $link); - } - } - - /** - * Render a page local link - * - * @param string $hash hash link identifier - * @param string $name name for the link - * @param bool $returnonly whether to return html or write to doc attribute - * @return void|string writes to doc attribute or returns html depends on $returnonly - */ - function locallink($hash, $name = null, $returnonly = false) { - global $ID; - $name = $this->_getLinkTitle($name, $hash, $isImage); - $hash = $this->_headerToLink($hash); - $title = $ID.' ↵'; - - $doc = '<a href="#'.$hash.'" title="'.$title.'" class="wikilink1">'; - $doc .= $name; - $doc .= '</a>'; - - if($returnonly) { - return $doc; - } else { - $this->doc .= $doc; - } - } - - /** - * Render an internal Wiki Link - * - * $search,$returnonly & $linktype are not for the renderer but are used - * elsewhere - no need to implement them in other renderers - * - * @author Andreas Gohr <andi@splitbrain.org> - * @param string $id pageid - * @param string|null $name link name - * @param string|null $search adds search url param - * @param bool $returnonly whether to return html or write to doc attribute - * @param string $linktype type to set use of headings - * @return void|string writes to doc attribute or returns html depends on $returnonly - */ - function internallink($id, $name = null, $search = null, $returnonly = false, $linktype = 'content') { - global $conf; - global $ID; - global $INFO; - - $params = ''; - $parts = explode('?', $id, 2); - if(count($parts) === 2) { - $id = $parts[0]; - $params = $parts[1]; - } - - // For empty $id we need to know the current $ID - // We need this check because _simpleTitle needs - // correct $id and resolve_pageid() use cleanID($id) - // (some things could be lost) - if($id === '') { - $id = $ID; - } - - // default name is based on $id as given - $default = $this->_simpleTitle($id); - - // now first resolve and clean up the $id - resolve_pageid(getNS($ID), $id, $exists, $this->date_at, true); - - $link = array(); - $name = $this->_getLinkTitle($name, $default, $isImage, $id, $linktype); - if(!$isImage) { - if($exists) { - $class = 'wikilink1'; - } else { - $class = 'wikilink2'; - $link['rel'] = 'nofollow'; - } - } else { - $class = 'media'; - } - - //keep hash anchor - @list($id, $hash) = explode('#', $id, 2); - if(!empty($hash)) $hash = $this->_headerToLink($hash); - - //prepare for formating - $link['target'] = $conf['target']['wiki']; - $link['style'] = ''; - $link['pre'] = ''; - $link['suf'] = ''; - // highlight link to current page - if($id == $INFO['id']) { - $link['pre'] = '<span class="curid">'; - $link['suf'] = '</span>'; - } - $link['more'] = ''; - $link['class'] = $class; - if($this->date_at) { - $params = $params.'&at='.rawurlencode($this->date_at); - } - $link['url'] = wl($id, $params); - $link['name'] = $name; - $link['title'] = $id; - //add search string - if($search) { - ($conf['userewrite']) ? $link['url'] .= '?' : $link['url'] .= '&'; - if(is_array($search)) { - $search = array_map('rawurlencode', $search); - $link['url'] .= 's[]='.join('&s[]=', $search); - } else { - $link['url'] .= 's='.rawurlencode($search); - } - } - - //keep hash - if($hash) $link['url'] .= '#'.$hash; - - //output formatted - if($returnonly) { - return $this->_formatLink($link); - } else { - $this->doc .= $this->_formatLink($link); - } - } - - /** - * Render an external link - * - * @param string $url full URL with scheme - * @param string|array $name name for the link, array for media file - * @param bool $returnonly whether to return html or write to doc attribute - * @return void|string writes to doc attribute or returns html depends on $returnonly - */ - function externallink($url, $name = null, $returnonly = false) { - global $conf; - - $name = $this->_getLinkTitle($name, $url, $isImage); - - // url might be an attack vector, only allow registered protocols - if(is_null($this->schemes)) $this->schemes = getSchemes(); - list($scheme) = explode('://', $url); - $scheme = strtolower($scheme); - if(!in_array($scheme, $this->schemes)) $url = ''; - - // is there still an URL? - if(!$url) { - if($returnonly) { - return $name; - } else { - $this->doc .= $name; - } - return; - } - - // set class - if(!$isImage) { - $class = 'urlextern'; - } else { - $class = 'media'; - } - - //prepare for formating - $link = array(); - $link['target'] = $conf['target']['extern']; - $link['style'] = ''; - $link['pre'] = ''; - $link['suf'] = ''; - $link['more'] = ''; - $link['class'] = $class; - $link['url'] = $url; - $link['rel'] = ''; - - $link['name'] = $name; - $link['title'] = $this->_xmlEntities($url); - if($conf['relnofollow']) $link['rel'] .= ' nofollow'; - if($conf['target']['extern']) $link['rel'] .= ' noopener'; - - //output formatted - if($returnonly) { - return $this->_formatLink($link); - } else { - $this->doc .= $this->_formatLink($link); - } - } - - /** - * Render an interwiki link - * - * You may want to use $this->_resolveInterWiki() here - * - * @param string $match original link - probably not much use - * @param string|array $name name for the link, array for media file - * @param string $wikiName indentifier (shortcut) for the remote wiki - * @param string $wikiUri the fragment parsed from the original link - * @param bool $returnonly whether to return html or write to doc attribute - * @return void|string writes to doc attribute or returns html depends on $returnonly - */ - function interwikilink($match, $name = null, $wikiName, $wikiUri, $returnonly = false) { - global $conf; - - $link = array(); - $link['target'] = $conf['target']['interwiki']; - $link['pre'] = ''; - $link['suf'] = ''; - $link['more'] = ''; - $link['name'] = $this->_getLinkTitle($name, $wikiUri, $isImage); - $link['rel'] = ''; - - //get interwiki URL - $exists = null; - $url = $this->_resolveInterWiki($wikiName, $wikiUri, $exists); - - if(!$isImage) { - $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $wikiName); - $link['class'] = "interwiki iw_$class"; - } else { - $link['class'] = 'media'; - } - - //do we stay at the same server? Use local target - if(strpos($url, DOKU_URL) === 0 OR strpos($url, DOKU_BASE) === 0) { - $link['target'] = $conf['target']['wiki']; - } - if($exists !== null && !$isImage) { - if($exists) { - $link['class'] .= ' wikilink1'; - } else { - $link['class'] .= ' wikilink2'; - $link['rel'] .= ' nofollow'; - } - } - if($conf['target']['interwiki']) $link['rel'] .= ' noopener'; - - $link['url'] = $url; - $link['title'] = htmlspecialchars($link['url']); - - //output formatted - if($returnonly) { - return $this->_formatLink($link); - } else { - $this->doc .= $this->_formatLink($link); - } - } - - /** - * Link to windows share - * - * @param string $url the link - * @param string|array $name name for the link, array for media file - * @param bool $returnonly whether to return html or write to doc attribute - * @return void|string writes to doc attribute or returns html depends on $returnonly - */ - function windowssharelink($url, $name = null, $returnonly = false) { - global $conf; - - //simple setup - $link = array(); - $link['target'] = $conf['target']['windows']; - $link['pre'] = ''; - $link['suf'] = ''; - $link['style'] = ''; - - $link['name'] = $this->_getLinkTitle($name, $url, $isImage); - if(!$isImage) { - $link['class'] = 'windows'; - } else { - $link['class'] = 'media'; - } - - $link['title'] = $this->_xmlEntities($url); - $url = str_replace('\\', '/', $url); - $url = 'file:///'.$url; - $link['url'] = $url; - - //output formatted - if($returnonly) { - return $this->_formatLink($link); - } else { - $this->doc .= $this->_formatLink($link); - } - } - - /** - * Render a linked E-Mail Address - * - * Honors $conf['mailguard'] setting - * - * @param string $address Email-Address - * @param string|array $name name for the link, array for media file - * @param bool $returnonly whether to return html or write to doc attribute - * @return void|string writes to doc attribute or returns html depends on $returnonly - */ - function emaillink($address, $name = null, $returnonly = false) { - global $conf; - //simple setup - $link = array(); - $link['target'] = ''; - $link['pre'] = ''; - $link['suf'] = ''; - $link['style'] = ''; - $link['more'] = ''; - - $name = $this->_getLinkTitle($name, '', $isImage); - if(!$isImage) { - $link['class'] = 'mail'; - } else { - $link['class'] = 'media'; - } - - $address = $this->_xmlEntities($address); - $address = obfuscate($address); - $title = $address; - - if(empty($name)) { - $name = $address; - } - - if($conf['mailguard'] == 'visible') $address = rawurlencode($address); - - $link['url'] = 'mailto:'.$address; - $link['name'] = $name; - $link['title'] = $title; - - //output formatted - if($returnonly) { - return $this->_formatLink($link); - } else { - $this->doc .= $this->_formatLink($link); - } - } - - /** - * Render an internal media file - * - * @param string $src media ID - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - * @param string $linking linkonly|detail|nolink - * @param bool $return return HTML instead of adding to $doc - * @return void|string writes to doc attribute or returns html depends on $return - */ - function internalmedia($src, $title = null, $align = null, $width = null, - $height = null, $cache = null, $linking = null, $return = false) { - global $ID; - if (strpos($src, '#') !== false) { - list($src, $hash) = explode('#', $src, 2); - } - resolve_mediaid(getNS($ID), $src, $exists, $this->date_at, true); - - $noLink = false; - $render = ($linking == 'linkonly') ? false : true; - $link = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render); - - list($ext, $mime) = mimetype($src, false); - if(substr($mime, 0, 5) == 'image' && $render) { - $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src)), ($linking == 'direct')); - } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) { - // don't link movies - $noLink = true; - } else { - // add file icons - $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext); - $link['class'] .= ' mediafile mf_'.$class; - $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache , 'rev'=>$this->_getLastMediaRevisionAt($src)), true); - if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')'; - } - - if (!empty($hash)) $link['url'] .= '#'.$hash; - - //markup non existing files - if(!$exists) { - $link['class'] .= ' wikilink2'; - } - - //output formatted - if($return) { - if($linking == 'nolink' || $noLink) return $link['name']; - else return $this->_formatLink($link); - } else { - if($linking == 'nolink' || $noLink) $this->doc .= $link['name']; - else $this->doc .= $this->_formatLink($link); - } - } - - /** - * Render an external media file - * - * @param string $src full media URL - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - * @param string $linking linkonly|detail|nolink - * @param bool $return return HTML instead of adding to $doc - * @return void|string writes to doc attribute or returns html depends on $return - */ - function externalmedia($src, $title = null, $align = null, $width = null, - $height = null, $cache = null, $linking = null, $return = false) { - if(link_isinterwiki($src)){ - list($shortcut, $reference) = explode('>', $src, 2); - $exists = null; - $src = $this->_resolveInterWiki($shortcut, $reference, $exists); - } - list($src, $hash) = explode('#', $src, 2); - $noLink = false; - $render = ($linking == 'linkonly') ? false : true; - $link = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render); - - $link['url'] = ml($src, array('cache' => $cache)); - - list($ext, $mime) = mimetype($src, false); - if(substr($mime, 0, 5) == 'image' && $render) { - // link only jpeg images - // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = true; - } elseif(($mime == 'application/x-shockwave-flash' || media_supportedav($mime)) && $render) { - // don't link movies - $noLink = true; - } else { - // add file icons - $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext); - $link['class'] .= ' mediafile mf_'.$class; - } - - if($hash) $link['url'] .= '#'.$hash; - - //output formatted - if($return) { - if($linking == 'nolink' || $noLink) return $link['name']; - else return $this->_formatLink($link); - } else { - if($linking == 'nolink' || $noLink) $this->doc .= $link['name']; - else $this->doc .= $this->_formatLink($link); - } - } - - /** - * Renders an RSS feed - * - * @param string $url URL of the feed - * @param array $params Finetuning of the output - * - * @author Andreas Gohr <andi@splitbrain.org> - */ - function rss($url, $params) { - global $lang; - global $conf; - - require_once(DOKU_INC.'inc/FeedParser.php'); - $feed = new FeedParser(); - $feed->set_feed_url($url); - - //disable warning while fetching - if(!defined('DOKU_E_LEVEL')) { - $elvl = error_reporting(E_ERROR); - } - $rc = $feed->init(); - if(isset($elvl)) { - error_reporting($elvl); - } - - if($params['nosort']) $feed->enable_order_by_date(false); - - //decide on start and end - if($params['reverse']) { - $mod = -1; - $start = $feed->get_item_quantity() - 1; - $end = $start - ($params['max']); - $end = ($end < -1) ? -1 : $end; - } else { - $mod = 1; - $start = 0; - $end = $feed->get_item_quantity(); - $end = ($end > $params['max']) ? $params['max'] : $end; - } - - $this->doc .= '<ul class="rss">'; - if($rc) { - for($x = $start; $x != $end; $x += $mod) { - $item = $feed->get_item($x); - $this->doc .= '<li><div class="li">'; - // support feeds without links - $lnkurl = $item->get_permalink(); - if($lnkurl) { - // title is escaped by SimplePie, we unescape here because it - // is escaped again in externallink() FS#1705 - $this->externallink( - $item->get_permalink(), - html_entity_decode($item->get_title(), ENT_QUOTES, 'UTF-8') - ); - } else { - $this->doc .= ' '.$item->get_title(); - } - if($params['author']) { - $author = $item->get_author(0); - if($author) { - $name = $author->get_name(); - if(!$name) $name = $author->get_email(); - if($name) $this->doc .= ' '.$lang['by'].' '.hsc($name); - } - } - if($params['date']) { - $this->doc .= ' ('.$item->get_local_date($conf['dformat']).')'; - } - if($params['details']) { - $this->doc .= '<div class="detail">'; - if($conf['htmlok']) { - $this->doc .= $item->get_description(); - } else { - $this->doc .= strip_tags($item->get_description()); - } - $this->doc .= '</div>'; - } - - $this->doc .= '</div></li>'; - } - } else { - $this->doc .= '<li><div class="li">'; - $this->doc .= '<em>'.$lang['rssfailed'].'</em>'; - $this->externallink($url); - if($conf['allowdebug']) { - $this->doc .= '<!--'.hsc($feed->error).'-->'; - } - $this->doc .= '</div></li>'; - } - $this->doc .= '</ul>'; - } - - /** - * Start a table - * - * @param int $maxcols maximum number of columns - * @param int $numrows NOT IMPLEMENTED - * @param int $pos byte position in the original source - * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input - */ - function table_open($maxcols = null, $numrows = null, $pos = null, $classes = null) { - // initialize the row counter used for classes - $this->_counter['row_counter'] = 0; - $class = 'table'; - if($classes !== null) { - if(is_array($classes)) $classes = join(' ', $classes); - $class .= ' ' . $classes; - } - if($pos !== null) { - $hid = $this->_headerToLink($class, true); - $data = array(); - $data['target'] = 'table'; - $data['name'] = ''; - $data['hid'] = $hid; - $class .= ' '.$this->startSectionEdit($pos, $data); - } - $this->doc .= '<div class="'.$class.'"><table class="inline">'. - DOKU_LF; - } - - /** - * Close a table - * - * @param int $pos byte position in the original source - */ - function table_close($pos = null) { - $this->doc .= '</table></div>'.DOKU_LF; - if($pos !== null) { - $this->finishSectionEdit($pos); - } - } - - /** - * Open a table header - */ - function tablethead_open() { - $this->doc .= DOKU_TAB.'<thead>'.DOKU_LF; - } - - /** - * Close a table header - */ - function tablethead_close() { - $this->doc .= DOKU_TAB.'</thead>'.DOKU_LF; - } - - /** - * Open a table body - */ - function tabletbody_open() { - $this->doc .= DOKU_TAB.'<tbody>'.DOKU_LF; - } - - /** - * Close a table body - */ - function tabletbody_close() { - $this->doc .= DOKU_TAB.'</tbody>'.DOKU_LF; - } - - /** - * Open a table footer - */ - function tabletfoot_open() { - $this->doc .= DOKU_TAB.'<tfoot>'.DOKU_LF; - } - - /** - * Close a table footer - */ - function tabletfoot_close() { - $this->doc .= DOKU_TAB.'</tfoot>'.DOKU_LF; - } - - /** - * Open a table row - * - * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input - */ - function tablerow_open($classes = null) { - // initialize the cell counter used for classes - $this->_counter['cell_counter'] = 0; - $class = 'row'.$this->_counter['row_counter']++; - if($classes !== null) { - if(is_array($classes)) $classes = join(' ', $classes); - $class .= ' ' . $classes; - } - $this->doc .= DOKU_TAB.'<tr class="'.$class.'">'.DOKU_LF.DOKU_TAB.DOKU_TAB; - } - - /** - * Close a table row - */ - function tablerow_close() { - $this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF; - } - - /** - * Open a table header cell - * - * @param int $colspan - * @param string $align left|center|right - * @param int $rowspan - * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input - */ - function tableheader_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) { - $class = 'class="col'.$this->_counter['cell_counter']++; - if(!is_null($align)) { - $class .= ' '.$align.'align'; - } - if($classes !== null) { - if(is_array($classes)) $classes = join(' ', $classes); - $class .= ' ' . $classes; - } - $class .= '"'; - $this->doc .= '<th '.$class; - if($colspan > 1) { - $this->_counter['cell_counter'] += $colspan - 1; - $this->doc .= ' colspan="'.$colspan.'"'; - } - if($rowspan > 1) { - $this->doc .= ' rowspan="'.$rowspan.'"'; - } - $this->doc .= '>'; - } - - /** - * Close a table header cell - */ - function tableheader_close() { - $this->doc .= '</th>'; - } - - /** - * Open a table cell - * - * @param int $colspan - * @param string $align left|center|right - * @param int $rowspan - * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input - */ - function tablecell_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) { - $class = 'class="col'.$this->_counter['cell_counter']++; - if(!is_null($align)) { - $class .= ' '.$align.'align'; - } - if($classes !== null) { - if(is_array($classes)) $classes = join(' ', $classes); - $class .= ' ' . $classes; - } - $class .= '"'; - $this->doc .= '<td '.$class; - if($colspan > 1) { - $this->_counter['cell_counter'] += $colspan - 1; - $this->doc .= ' colspan="'.$colspan.'"'; - } - if($rowspan > 1) { - $this->doc .= ' rowspan="'.$rowspan.'"'; - } - $this->doc .= '>'; - } - - /** - * Close a table cell - */ - function tablecell_close() { - $this->doc .= '</td>'; - } - - /** - * Returns the current header level. - * (required e.g. by the filelist plugin) - * - * @return int The current header level - */ - function getLastlevel() { - return $this->lastlevel; - } - - #region Utility functions - - /** - * Build a link - * - * Assembles all parts defined in $link returns HTML for the link - * - * @param array $link attributes of a link - * @return string - * - * @author Andreas Gohr <andi@splitbrain.org> - */ - function _formatLink($link) { - //make sure the url is XHTML compliant (skip mailto) - if(substr($link['url'], 0, 7) != 'mailto:') { - $link['url'] = str_replace('&', '&', $link['url']); - $link['url'] = str_replace('&amp;', '&', $link['url']); - } - //remove double encodings in titles - $link['title'] = str_replace('&amp;', '&', $link['title']); - - // be sure there are no bad chars in url or title - // (we can't do this for name because it can contain an img tag) - $link['url'] = strtr($link['url'], array('>' => '%3E', '<' => '%3C', '"' => '%22')); - $link['title'] = strtr($link['title'], array('>' => '>', '<' => '<', '"' => '"')); - - $ret = ''; - $ret .= $link['pre']; - $ret .= '<a href="'.$link['url'].'"'; - if(!empty($link['class'])) $ret .= ' class="'.$link['class'].'"'; - if(!empty($link['target'])) $ret .= ' target="'.$link['target'].'"'; - if(!empty($link['title'])) $ret .= ' title="'.$link['title'].'"'; - if(!empty($link['style'])) $ret .= ' style="'.$link['style'].'"'; - if(!empty($link['rel'])) $ret .= ' rel="'.trim($link['rel']).'"'; - if(!empty($link['more'])) $ret .= ' '.$link['more']; - $ret .= '>'; - $ret .= $link['name']; - $ret .= '</a>'; - $ret .= $link['suf']; - return $ret; - } - - /** - * Renders internal and external media - * - * @author Andreas Gohr <andi@splitbrain.org> - * @param string $src media ID - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - * @param bool $render should the media be embedded inline or just linked - * @return string - */ - function _media($src, $title = null, $align = null, $width = null, - $height = null, $cache = null, $render = true) { - - $ret = ''; - - list($ext, $mime) = mimetype($src); - if(substr($mime, 0, 5) == 'image') { - // first get the $title - if(!is_null($title)) { - $title = $this->_xmlEntities($title); - } elseif($ext == 'jpg' || $ext == 'jpeg') { - //try to use the caption from IPTC/EXIF - require_once(DOKU_INC.'inc/JpegMeta.php'); - $jpeg = new JpegMeta(mediaFN($src)); - if($jpeg !== false) $cap = $jpeg->getTitle(); - if(!empty($cap)) { - $title = $this->_xmlEntities($cap); - } - } - if(!$render) { - // if the picture is not supposed to be rendered - // return the title of the picture - if(!$title) { - // just show the sourcename - $title = $this->_xmlEntities(utf8_basename(noNS($src))); - } - return $title; - } - //add image tag - $ret .= '<img src="'.ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src))).'"'; - $ret .= ' class="media'.$align.'"'; - - if($title) { - $ret .= ' title="'.$title.'"'; - $ret .= ' alt="'.$title.'"'; - } else { - $ret .= ' alt=""'; - } - - if(!is_null($width)) - $ret .= ' width="'.$this->_xmlEntities($width).'"'; - - if(!is_null($height)) - $ret .= ' height="'.$this->_xmlEntities($height).'"'; - - $ret .= ' />'; - - } elseif(media_supportedav($mime, 'video') || media_supportedav($mime, 'audio')) { - // first get the $title - $title = !is_null($title) ? $this->_xmlEntities($title) : false; - if(!$render) { - // if the file is not supposed to be rendered - // return the title of the file (just the sourcename if there is no title) - return $title ? $title : $this->_xmlEntities(utf8_basename(noNS($src))); - } - - $att = array(); - $att['class'] = "media$align"; - if($title) { - $att['title'] = $title; - } - - if(media_supportedav($mime, 'video')) { - //add video - $ret .= $this->_video($src, $width, $height, $att); - } - if(media_supportedav($mime, 'audio')) { - //add audio - $ret .= $this->_audio($src, $att); - } - - } elseif($mime == 'application/x-shockwave-flash') { - if(!$render) { - // if the flash is not supposed to be rendered - // return the title of the flash - if(!$title) { - // just show the sourcename - $title = utf8_basename(noNS($src)); - } - return $this->_xmlEntities($title); - } - - $att = array(); - $att['class'] = "media$align"; - if($align == 'right') $att['align'] = 'right'; - if($align == 'left') $att['align'] = 'left'; - $ret .= html_flashobject( - ml($src, array('cache' => $cache), true, '&'), $width, $height, - array('quality' => 'high'), - null, - $att, - $this->_xmlEntities($title) - ); - } elseif($title) { - // well at least we have a title to display - $ret .= $this->_xmlEntities($title); - } else { - // just show the sourcename - $ret .= $this->_xmlEntities(utf8_basename(noNS($src))); - } - - return $ret; - } - - /** - * Escape string for output - * - * @param $string - * @return string - */ - function _xmlEntities($string) { - return htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); - } - - /** - * Creates a linkid from a headline - * - * @author Andreas Gohr <andi@splitbrain.org> - * @param string $title The headline title - * @param boolean $create Create a new unique ID? - * @return string - */ - function _headerToLink($title, $create = false) { - if($create) { - return sectionID($title, $this->headers); - } else { - $check = false; - return sectionID($title, $check); - } - } - - /** - * Construct a title and handle images in titles - * - * @author Harry Fuecks <hfuecks@gmail.com> - * @param string|array $title either string title or media array - * @param string $default default title if nothing else is found - * @param bool $isImage will be set to true if it's a media file - * @param null|string $id linked page id (used to extract title from first heading) - * @param string $linktype content|navigation - * @return string HTML of the title, might be full image tag or just escaped text - */ - function _getLinkTitle($title, $default, &$isImage, $id = null, $linktype = 'content') { - $isImage = false; - if(is_array($title)) { - $isImage = true; - return $this->_imageTitle($title); - } elseif(is_null($title) || trim($title) == '') { - if(useHeading($linktype) && $id) { - $heading = p_get_first_heading($id); - if(!blank($heading)) { - return $this->_xmlEntities($heading); - } - } - return $this->_xmlEntities($default); - } else { - return $this->_xmlEntities($title); - } - } - - /** - * Returns HTML code for images used in link titles - * - * @author Andreas Gohr <andi@splitbrain.org> - * @param array $img - * @return string HTML img tag or similar - */ - function _imageTitle($img) { - global $ID; - - // some fixes on $img['src'] - // see internalmedia() and externalmedia() - list($img['src']) = explode('#', $img['src'], 2); - if($img['type'] == 'internalmedia') { - resolve_mediaid(getNS($ID), $img['src'], $exists ,$this->date_at, true); - } - - return $this->_media( - $img['src'], - $img['title'], - $img['align'], - $img['width'], - $img['height'], - $img['cache'] - ); - } - - /** - * helperfunction to return a basic link to a media - * - * used in internalmedia() and externalmedia() - * - * @author Pierre Spring <pierre.spring@liip.ch> - * @param string $src media ID - * @param string $title descriptive text - * @param string $align left|center|right - * @param int $width width of media in pixel - * @param int $height height of media in pixel - * @param string $cache cache|recache|nocache - * @param bool $render should the media be embedded inline or just linked - * @return array associative array with link config - */ - function _getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render) { - global $conf; - - $link = array(); - $link['class'] = 'media'; - $link['style'] = ''; - $link['pre'] = ''; - $link['suf'] = ''; - $link['more'] = ''; - $link['target'] = $conf['target']['media']; - if($conf['target']['media']) $link['rel'] = 'noopener'; - $link['title'] = $this->_xmlEntities($src); - $link['name'] = $this->_media($src, $title, $align, $width, $height, $cache, $render); - - return $link; - } - - /** - * Embed video(s) in HTML - * - * @author Anika Henke <anika@selfthinker.org> - * @author Schplurtz le Déboulonné <Schplurtz@laposte.net> - * - * @param string $src - ID of video to embed - * @param int $width - width of the video in pixels - * @param int $height - height of the video in pixels - * @param array $atts - additional attributes for the <video> tag - * @return string - */ - function _video($src, $width, $height, $atts = null) { - // prepare width and height - if(is_null($atts)) $atts = array(); - $atts['width'] = (int) $width; - $atts['height'] = (int) $height; - if(!$atts['width']) $atts['width'] = 320; - if(!$atts['height']) $atts['height'] = 240; - - $posterUrl = ''; - $files = array(); - $tracks = array(); - $isExternal = media_isexternal($src); - - if ($isExternal) { - // take direct source for external files - list(/*ext*/, $srcMime) = mimetype($src); - $files[$srcMime] = $src; - } else { - // prepare alternative formats - $extensions = array('webm', 'ogv', 'mp4'); - $files = media_alternativefiles($src, $extensions); - $poster = media_alternativefiles($src, array('jpg', 'png')); - $tracks = media_trackfiles($src); - if(!empty($poster)) { - $posterUrl = ml(reset($poster), '', true, '&'); - } - } - - $out = ''; - // open video tag - $out .= '<video '.buildAttributes($atts).' controls="controls"'; - if($posterUrl) $out .= ' poster="'.hsc($posterUrl).'"'; - $out .= '>'.NL; - $fallback = ''; - - // output source for each alternative video format - foreach($files as $mime => $file) { - if ($isExternal) { - $url = $file; - $linkType = 'externalmedia'; - } else { - $url = ml($file, '', true, '&'); - $linkType = 'internalmedia'; - } - $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file))); - - $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL; - // alternative content (just a link to the file) - $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true); - } - - // output each track if any - foreach( $tracks as $trackid => $info ) { - list( $kind, $srclang ) = array_map( 'hsc', $info ); - $out .= "<track kind=\"$kind\" srclang=\"$srclang\" "; - $out .= "label=\"$srclang\" "; - $out .= 'src="'.ml($trackid, '', true).'">'.NL; - } - - // finish - $out .= $fallback; - $out .= '</video>'.NL; - return $out; - } - - /** - * Embed audio in HTML - * - * @author Anika Henke <anika@selfthinker.org> - * - * @param string $src - ID of audio to embed - * @param array $atts - additional attributes for the <audio> tag - * @return string - */ - function _audio($src, $atts = array()) { - $files = array(); - $isExternal = media_isexternal($src); - - if ($isExternal) { - // take direct source for external files - list(/*ext*/, $srcMime) = mimetype($src); - $files[$srcMime] = $src; - } else { - // prepare alternative formats - $extensions = array('ogg', 'mp3', 'wav'); - $files = media_alternativefiles($src, $extensions); - } - - $out = ''; - // open audio tag - $out .= '<audio '.buildAttributes($atts).' controls="controls">'.NL; - $fallback = ''; - - // output source for each alternative audio format - foreach($files as $mime => $file) { - if ($isExternal) { - $url = $file; - $linkType = 'externalmedia'; - } else { - $url = ml($file, '', true, '&'); - $linkType = 'internalmedia'; - } - $title = $atts['title'] ? $atts['title'] : $this->_xmlEntities(utf8_basename(noNS($file))); - - $out .= '<source src="'.hsc($url).'" type="'.$mime.'" />'.NL; - // alternative content (just a link to the file) - $fallback .= $this->$linkType($file, $title, null, null, null, $cache = null, $linking = 'linkonly', $return = true); - } - - // finish - $out .= $fallback; - $out .= '</audio>'.NL; - return $out; - } - - /** - * _getLastMediaRevisionAt is a helperfunction to internalmedia() and _media() - * which returns an existing media revision less or equal to rev or date_at - * - * @author lisps - * @param string $media_id - * @access protected - * @return string revision ('' for current) - */ - function _getLastMediaRevisionAt($media_id){ - if(!$this->date_at || media_isexternal($media_id)) return ''; - $pagelog = new MediaChangeLog($media_id); - return $pagelog->getLastRevisionAt($this->date_at); - } - - #endregion -} - -//Setup VIM: ex: et ts=4 : diff --git a/wiki/inc/parser/xhtmlsummary.php b/wiki/inc/parser/xhtmlsummary.php deleted file mode 100644 index 867b71f..0000000 --- a/wiki/inc/parser/xhtmlsummary.php +++ /dev/null @@ -1,89 +0,0 @@ -<?php -if(!defined('DOKU_INC')) die('meh.'); - -/** - * The summary XHTML form selects either up to the first two paragraphs - * it find in a page or the first section (whichever comes first) - * It strips out the table of contents if one exists - * Section divs are not used - everything should be nested in a single - * div with CSS class "page" - * Headings have their a name link removed and section editing links - * removed - * It also attempts to capture the first heading in a page for - * use as the title of the page. - * - * - * @author Harry Fuecks <hfuecks@gmail.com> - * @todo Is this currently used anywhere? Should it? - */ -class Doku_Renderer_xhtmlsummary extends Doku_Renderer_xhtml { - - // Namespace these variables to - // avoid clashes with parent classes - var $sum_paragraphs = 0; - var $sum_capture = true; - var $sum_inSection = false; - var $sum_summary = ''; - var $sum_pageTitle = false; - - function document_start() { - $this->doc .= DOKU_LF.'<div>'.DOKU_LF; - } - - function document_end() { - $this->doc = $this->sum_summary; - $this->doc .= DOKU_LF.'</div>'.DOKU_LF; - } - - // FIXME not supported anymore - function toc_open() { - $this->sum_summary .= $this->doc; - } - - // FIXME not supported anymore - function toc_close() { - $this->doc = ''; - } - - function header($text, $level, $pos) { - if ( !$this->sum_pageTitle ) { - $this->info['sum_pagetitle'] = $text; - $this->sum_pageTitle = true; - } - $this->doc .= DOKU_LF.'<h'.$level.'>'; - $this->doc .= $this->_xmlEntities($text); - $this->doc .= "</h$level>".DOKU_LF; - } - - function section_open($level) { - if ( $this->sum_capture ) { - $this->sum_inSection = true; - } - } - - function section_close() { - if ( $this->sum_capture && $this->sum_inSection ) { - $this->sum_summary .= $this->doc; - $this->sum_capture = false; - } - } - - function p_open() { - if ( $this->sum_capture && $this->sum_paragraphs < 2 ) { - $this->sum_paragraphs++; - } - parent :: p_open(); - } - - function p_close() { - parent :: p_close(); - if ( $this->sum_capture && $this->sum_paragraphs >= 2 ) { - $this->sum_summary .= $this->doc; - $this->sum_capture = false; - } - } - -} - - -//Setup VIM: ex: et ts=2 : |