diff options
Diffstat (limited to 'inc/parser')
-rw-r--r-- | inc/parser/code.php | 12 | ||||
-rw-r--r-- | inc/parser/handler.php | 1847 | ||||
-rw-r--r-- | inc/parser/lexer.php | 614 | ||||
-rw-r--r-- | inc/parser/metadata.php | 122 | ||||
-rw-r--r-- | inc/parser/parser.php | 1023 | ||||
-rw-r--r-- | inc/parser/renderer.php | 211 | ||||
-rw-r--r-- | inc/parser/xhtml.php | 291 | ||||
-rw-r--r-- | inc/parser/xhtmlsummary.php | 43 |
8 files changed, 935 insertions, 3228 deletions
diff --git a/inc/parser/code.php b/inc/parser/code.php index f91f1d228..043ce5be9 100644 --- a/inc/parser/code.php +++ b/inc/parser/code.php @@ -4,10 +4,8 @@ * * @author Andreas Gohr <andi@splitbrain.org> */ -if(!defined('DOKU_INC')) die('meh.'); - class Doku_Renderer_code extends Doku_Renderer { - var $_codeblock = 0; + protected $_codeblock = 0; /** * Send the wanted code block to the browser @@ -18,7 +16,7 @@ class Doku_Renderer_code extends Doku_Renderer { * @param string $language * @param string $filename */ - function code($text, $language = null, $filename = '') { + public function code($text, $language = null, $filename = '') { global $INPUT; if(!$language) $language = 'txt'; $language = preg_replace(PREG_PATTERN_VALID_LANGUAGE, '', $language); @@ -49,14 +47,14 @@ class Doku_Renderer_code extends Doku_Renderer { * @param string $language * @param string $filename */ - function file($text, $language = null, $filename = '') { + public 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() { + public function document_end() { http_status(404); echo '404 - Not found'; exit; @@ -67,7 +65,7 @@ class Doku_Renderer_code extends Doku_Renderer { * * @returns string 'code' */ - function getFormat() { + public function getFormat() { return 'code'; } } diff --git a/inc/parser/handler.php b/inc/parser/handler.php index 780c6cf48..6d4c6b97e 100644 --- a/inc/parser/handler.php +++ b/inc/parser/handler.php @@ -1,44 +1,76 @@ <?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; +use dokuwiki\Parsing\Handler\Block; +use dokuwiki\Parsing\Handler\CallWriter; +use dokuwiki\Parsing\Handler\CallWriterInterface; +use dokuwiki\Parsing\Handler\Lists; +use dokuwiki\Parsing\Handler\Nest; +use dokuwiki\Parsing\Handler\Preformatted; +use dokuwiki\Parsing\Handler\Quote; +use dokuwiki\Parsing\Handler\Table; - var $CallWriter = null; +/** + * Class Doku_Handler + */ +class Doku_Handler { + /** @var CallWriterInterface */ + protected $callWriter = null; - var $calls = array(); + /** @var array The current CallWriter will write directly to this list of calls, Parser reads it */ + public $calls = array(); - var $status = array( + /** @var array internal status holders for some modes */ + protected $status = array( 'section' => false, 'doublequote' => 0, ); - var $rewriteBlocks = true; + /** @var bool should blocks be rewritten? FIXME seems to always be true */ + protected $rewriteBlocks = true; - function __construct() { - $this->CallWriter = new Doku_Handler_CallWriter($this); + /** + * Doku_Handler constructor. + */ + public function __construct() { + $this->callWriter = new CallWriter($this); } /** - * @param string $handler - * @param mixed $args - * @param integer|string $pos + * Add a new call by passing it to the current CallWriter + * + * @param string $handler handler method name (see mode handlers below) + * @param mixed $args arguments for this call + * @param int $pos byte position in the original source file */ - function _addCall($handler, $args, $pos) { + protected function addCall($handler, $args, $pos) { $call = array($handler,$args, $pos); - $this->CallWriter->writeCall($call); + $this->callWriter->writeCall($call); } - function addPluginCall($plugin, $args, $state, $pos, $match) { + /** + * Similar to addCall, but adds a plugin call + * + * @param string $plugin name of the plugin + * @param mixed $args arguments for this call + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @param string $match matched syntax + */ + protected function addPluginCall($plugin, $args, $state, $pos, $match) { $call = array('plugin',array($plugin, $args, $state, $match), $pos); - $this->CallWriter->writeCall($call); + $this->callWriter->writeCall($call); } - function _finalize(){ - - $this->CallWriter->finalise(); + /** + * Finishes handling + * + * Called from the parser. Calls finalise() on the call writer, closes open + * sections, rewrites blocks and adds document_start and document_end calls. + * + * @triggers PARSER_HANDLER_DONE + */ + public function finalize(){ + $this->callWriter->finalise(); if ( $this->status['section'] ) { $last_call = end($this->calls); @@ -46,7 +78,7 @@ class Doku_Handler { } if ( $this->rewriteBlocks ) { - $B = new Doku_Handler_Block(); + $B = new Block(); $this->calls = $B->process($this->calls); } @@ -60,9 +92,10 @@ class Doku_Handler { /** * fetch the current call and advance the pointer to the next one * + * @fixme seems to be unused? * @return bool|mixed */ - function fetch() { + public function fetch() { $call = current($this->calls); if($call !== false) { next($this->calls); //advance the pointer @@ -73,21 +106,125 @@ class Doku_Handler { /** + * 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; + } + + /** + * Simplifies handling for the formatting tags which all behave the same + * + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @param string $name actual mode name + */ + protected 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; + } + } + + + /** + * The following methods define the handlers for the different Syntax modes + * + * The handlers are called from dokuwiki\Parsing\Lexer\Lexer\invokeParser() + * + * @todo it might make sense to move these into their own class or merge them with the + * ParserMode classes some time. + */ + // region mode handlers + + /** * Special plugin handler * * This handler is called for all modes starting with 'plugin_'. - * An additional parameter with the plugin name is passed + * An additional parameter with the plugin name is passed. The plugin's handle() + * method is called here * * @author Andreas Gohr <andi@splitbrain.org> * - * @param string|integer $match - * @param string|integer $state - * @param integer $pos - * @param $pluginname - * - * @return bool + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @param string $pluginname name of the plugin + * @return bool mode handled? */ - function plugin($match, $state, $pos, $pluginname){ + public function plugin($match, $state, $pos, $pluginname){ $data = array($match); /** @var DokuWiki_Syntax_Plugin $plugin */ $plugin = plugin_load('syntax',$pluginname); @@ -100,16 +237,29 @@ class Doku_Handler { return true; } - function base($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function base($match, $state, $pos) { switch ( $state ) { case DOKU_LEXER_UNMATCHED: - $this->_addCall('cdata',array($match), $pos); + $this->addCall('cdata', array($match), $pos); return true; break; } + return false; } - function header($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function header($match, $state, $pos) { // get level and title $title = trim($match); $level = 7 - strspn($title,'='); @@ -117,98 +267,154 @@ class Doku_Handler { $title = trim($title,'='); $title = trim($title); - if ($this->status['section']) $this->_addCall('section_close',array(),$pos); + if ($this->status['section']) $this->addCall('section_close', array(), $pos); - $this->_addCall('header',array($title,$level,$pos), $pos); + $this->addCall('header', array($title, $level, $pos), $pos); - $this->_addCall('section_open',array($level),$pos); + $this->addCall('section_open', array($level), $pos); $this->status['section'] = true; return true; } - function notoc($match, $state, $pos) { - $this->_addCall('notoc',array(),$pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function notoc($match, $state, $pos) { + $this->addCall('notoc', array(), $pos); return true; } - function nocache($match, $state, $pos) { - $this->_addCall('nocache',array(),$pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function nocache($match, $state, $pos) { + $this->addCall('nocache', array(), $pos); return true; } - function linebreak($match, $state, $pos) { - $this->_addCall('linebreak',array(),$pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function linebreak($match, $state, $pos) { + $this->addCall('linebreak', array(), $pos); return true; } - function eol($match, $state, $pos) { - $this->_addCall('eol',array(),$pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function eol($match, $state, $pos) { + $this->addCall('eol', array(), $pos); return true; } - function hr($match, $state, $pos) { - $this->_addCall('hr',array(),$pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public 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 + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? */ - 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'); + public function strong($match, $state, $pos) { + $this->nestingTag($match, $state, $pos, 'strong'); return true; } - function emphasis($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'emphasis'); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function emphasis($match, $state, $pos) { + $this->nestingTag($match, $state, $pos, 'emphasis'); return true; } - function underline($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'underline'); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function underline($match, $state, $pos) { + $this->nestingTag($match, $state, $pos, 'underline'); return true; } - function monospace($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'monospace'); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function monospace($match, $state, $pos) { + $this->nestingTag($match, $state, $pos, 'monospace'); return true; } - function subscript($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'subscript'); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function subscript($match, $state, $pos) { + $this->nestingTag($match, $state, $pos, 'subscript'); return true; } - function superscript($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'superscript'); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function superscript($match, $state, $pos) { + $this->nestingTag($match, $state, $pos, 'superscript'); return true; } - function deleted($match, $state, $pos) { - $this->_nestingTag($match, $state, $pos, 'deleted'); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function deleted($match, $state, $pos) { + $this->nestingTag($match, $state, $pos, 'deleted'); return true; } - - function footnote($match, $state, $pos) { -// $this->_nestingTag($match, $state, $pos, 'footnote'); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function footnote($match, $state, $pos) { if (!isset($this->_footnote)) $this->_footnote = false; switch ( $state ) { @@ -216,146 +422,185 @@ class Doku_Handler { // 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); + $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); + $this->callWriter = new Nest($this->callWriter, 'footnote_close'); + $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); + $this->addCall('cdata', array($match), $pos); break; } $this->_footnote = false; + $this->addCall('footnote_close', array(), $pos); - $this->_addCall('footnote_close', array(), $pos); - $this->CallWriter->process(); - $ReWriter = & $this->CallWriter; - $this->CallWriter = & $ReWriter->CallWriter; + /** @var Nest $reWriter */ + $reWriter = $this->callWriter; + $this->callWriter = $reWriter->process(); break; case DOKU_LEXER_UNMATCHED: - $this->_addCall('cdata', array($match), $pos); + $this->addCall('cdata', array($match), $pos); break; } return true; } - function listblock($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public 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); + $this->callWriter = new Lists($this->callWriter); + $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; + $this->addCall('list_close', array(), $pos); + /** @var Lists $reWriter */ + $reWriter = $this->callWriter; + $this->callWriter = $reWriter->process(); break; case DOKU_LEXER_MATCHED: - $this->_addCall('list_item', array($match), $pos); + $this->addCall('list_item', array($match), $pos); break; case DOKU_LEXER_UNMATCHED: - $this->_addCall('cdata', array($match), $pos); + $this->addCall('cdata', array($match), $pos); break; } return true; } - function unformatted($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function unformatted($match, $state, $pos) { if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('unformatted',array($match), $pos); + $this->addCall('unformatted', array($match), $pos); } return true; } - function php($match, $state, $pos) { - global $conf; + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function php($match, $state, $pos) { if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('php',array($match), $pos); + $this->addCall('php', array($match), $pos); } return true; } - function phpblock($match, $state, $pos) { - global $conf; + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function phpblock($match, $state, $pos) { if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('phpblock',array($match), $pos); + $this->addCall('phpblock', array($match), $pos); } return true; } - function html($match, $state, $pos) { - global $conf; + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function html($match, $state, $pos) { if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('html',array($match), $pos); + $this->addCall('html', array($match), $pos); } return true; } - function htmlblock($match, $state, $pos) { - global $conf; + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function htmlblock($match, $state, $pos) { if ( $state == DOKU_LEXER_UNMATCHED ) { - $this->_addCall('htmlblock',array($match), $pos); + $this->addCall('htmlblock', array($match), $pos); } return true; } - function preformatted($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public 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); + $this->callWriter = new Preformatted($this->callWriter); + $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; + $this->addCall('preformatted_end', array(), $pos); + /** @var Preformatted $reWriter */ + $reWriter = $this->callWriter; + $this->callWriter = $reWriter->process(); break; case DOKU_LEXER_MATCHED: - $this->_addCall('preformatted_newline',array(), $pos); + $this->addCall('preformatted_newline', array(), $pos); break; case DOKU_LEXER_UNMATCHED: - $this->_addCall('preformatted_content',array($match), $pos); + $this->addCall('preformatted_content', array($match), $pos); break; } return true; } - function quote($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public 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); + $this->callWriter = new Quote($this->callWriter); + $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; + $this->addCall('quote_end', array(), $pos); + /** @var Lists $reWriter */ + $reWriter = $this->callWriter; + $this->callWriter = $reWriter->process(); break; case DOKU_LEXER_MATCHED: - $this->_addCall('quote_newline',array($match), $pos); + $this->addCall('quote_newline', array($match), $pos); break; case DOKU_LEXER_UNMATCHED: - $this->_addCall('cdata',array($match), $pos); + $this->addCall('cdata', array($match), $pos); break; } @@ -364,81 +609,23 @@ class Doku_Handler { } /** - * 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 + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? */ - 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) { + public function file($match, $state, $pos) { return $this->code($match, $state, $pos, 'file'); } - function code($match, $state, $pos, $type='code') { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @param string $type either 'code' or 'file' + * @return bool mode handled? + */ + public function code($match, $state, $pos, $type='code') { if ( $state == DOKU_LEXER_UNMATCHED ) { $matches = explode('>',$match,2); // Cut out variable options enclosed in [] @@ -455,76 +642,146 @@ class Doku_Handler { if (!empty($options[0])) { $param [] = $this->parse_highlight_options ($options[0]); } - $this->_addCall($type, $param, $pos); + $this->addCall($type, $param, $pos); } return true; } - function acronym($match, $state, $pos) { - $this->_addCall('acronym',array($match), $pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function acronym($match, $state, $pos) { + $this->addCall('acronym', array($match), $pos); return true; } - function smiley($match, $state, $pos) { - $this->_addCall('smiley',array($match), $pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function smiley($match, $state, $pos) { + $this->addCall('smiley', array($match), $pos); return true; } - function wordblock($match, $state, $pos) { - $this->_addCall('wordblock',array($match), $pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function wordblock($match, $state, $pos) { + $this->addCall('wordblock', array($match), $pos); return true; } - function entity($match, $state, $pos) { - $this->_addCall('entity',array($match), $pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function entity($match, $state, $pos) { + $this->addCall('entity', array($match), $pos); return true; } - function multiplyentity($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function multiplyentity($match, $state, $pos) { preg_match_all('/\d+/',$match,$matches); - $this->_addCall('multiplyentity',array($matches[0][0],$matches[0][1]), $pos); + $this->addCall('multiplyentity', array($matches[0][0], $matches[0][1]), $pos); return true; } - function singlequoteopening($match, $state, $pos) { - $this->_addCall('singlequoteopening',array(), $pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function singlequoteopening($match, $state, $pos) { + $this->addCall('singlequoteopening', array(), $pos); return true; } - function singlequoteclosing($match, $state, $pos) { - $this->_addCall('singlequoteclosing',array(), $pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function singlequoteclosing($match, $state, $pos) { + $this->addCall('singlequoteclosing', array(), $pos); return true; } - function apostrophe($match, $state, $pos) { - $this->_addCall('apostrophe',array(), $pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function apostrophe($match, $state, $pos) { + $this->addCall('apostrophe', array(), $pos); return true; } - function doublequoteopening($match, $state, $pos) { - $this->_addCall('doublequoteopening',array(), $pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function doublequoteopening($match, $state, $pos) { + $this->addCall('doublequoteopening', array(), $pos); $this->status['doublequote']++; return true; } - function doublequoteclosing($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function doublequoteclosing($match, $state, $pos) { if ($this->status['doublequote'] <= 0) { $this->doublequoteopening($match, $state, $pos); } else { - $this->_addCall('doublequoteclosing',array(), $pos); + $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); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function camelcaselink($match, $state, $pos) { + $this->addCall('camelcaselink', array($match), $pos); return true; } - /* - */ - function internallink($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function internallink($match, $state, $pos) { // Strip the opening and closing markup $link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match); @@ -543,42 +800,42 @@ class Doku_Handler { if ( link_isinterwiki($link[0]) ) { // Interwiki $interwiki = explode('>',$link[0],2); - $this->_addCall( + $this->addCall( 'interwikilink', array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]), $pos ); }elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) { // Windows Share - $this->_addCall( + $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( + $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( + $this->addCall( 'emaillink', array($link[0],$link[1]), $pos ); }elseif ( preg_match('!^#.+!',$link[0]) ){ // local link - $this->_addCall( + $this->addCall( 'locallink', array(substr($link[0],1),$link[1]), $pos ); }else{ // internal link - $this->_addCall( + $this->addCall( 'internallink', array($link[0],$link[1]), $pos @@ -588,20 +845,38 @@ class Doku_Handler { return true; } - function filelink($match, $state, $pos) { - $this->_addCall('filelink',array($match, null), $pos); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public 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); + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function windowssharelink($match, $state, $pos) { + $this->addCall('windowssharelink', array($match, null), $pos); return true; } - function media($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function media($match, $state, $pos) { $p = Doku_Handler_Parse_Media($match); - $this->_addCall( + $this->addCall( $p['type'], array($p['src'], $p['title'], $p['align'], $p['width'], $p['height'], $p['cache'], $p['linking']), @@ -610,7 +885,13 @@ class Doku_Handler { return true; } - function rss($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function rss($match, $state, $pos) { $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match); // get params @@ -635,11 +916,17 @@ class Doku_Handler { $p['refresh'] = 14400; // default to 4 hours } - $this->_addCall('rss',array($link,$p),$pos); + $this->addCall('rss', array($link, $p), $pos); return true; } - function externallink($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function externallink($match, $state, $pos) { $url = $match; $title = null; @@ -653,69 +940,82 @@ class Doku_Handler { $url = 'http://'.$url; } - $this->_addCall('externallink',array($url, $title), $pos); + $this->addCall('externallink', array($url, $title), $pos); return true; } - function emaillink($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function emaillink($match, $state, $pos) { $email = preg_replace(array('/^</','/>$/'),'',$match); - $this->_addCall('emaillink',array($email, null), $pos); + $this->addCall('emaillink', array($email, null), $pos); return true; } - function table($match, $state, $pos) { + /** + * @param string $match matched syntax + * @param int $state a LEXER_STATE_* constant + * @param int $pos byte position in the original source file + * @return bool mode handled? + */ + public function table($match, $state, $pos) { switch ( $state ) { case DOKU_LEXER_ENTER: - $ReWriter = new Doku_Handler_Table($this->CallWriter); - $this->CallWriter = & $ReWriter; + $this->callWriter = new Table($this->callWriter); - $this->_addCall('table_start', array($pos + 1), $pos); + $this->addCall('table_start', array($pos + 1), $pos); if ( trim($match) == '^' ) { - $this->_addCall('tableheader', array(), $pos); + $this->addCall('tableheader', array(), $pos); } else { - $this->_addCall('tablecell', array(), $pos); + $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; + $this->addCall('table_end', array($pos), $pos); + /** @var Table $reWriter */ + $reWriter = $this->callWriter; + $this->callWriter = $reWriter->process(); break; case DOKU_LEXER_UNMATCHED: if ( trim($match) != '' ) { - $this->_addCall('cdata',array($match), $pos); + $this->addCall('cdata', array($match), $pos); } break; case DOKU_LEXER_MATCHED: if ( $match == ' ' ){ - $this->_addCall('cdata', array($match), $pos); + $this->addCall('cdata', array($match), $pos); } else if ( preg_match('/:::/',$match) ) { - $this->_addCall('rowspan', array($match), $pos); + $this->addCall('rowspan', array($match), $pos); } else if ( preg_match('/\t+/',$match) ) { - $this->_addCall('table_align', array($match), $pos); + $this->addCall('table_align', array($match), $pos); } else if ( preg_match('/ {2,}/',$match) ) { - $this->_addCall('table_align', array($match), $pos); + $this->addCall('table_align', array($match), $pos); } else if ( $match == "\n|" ) { - $this->_addCall('table_row', array(), $pos); - $this->_addCall('tablecell', array(), $pos); + $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); + $this->addCall('table_row', array(), $pos); + $this->addCall('tableheader', array(), $pos); } else if ( $match == '|' ) { - $this->_addCall('tablecell', array(), $pos); + $this->addCall('tablecell', array(), $pos); } else if ( $match == '^' ) { - $this->_addCall('tableheader', array(), $pos); + $this->addCall('tableheader', array(), $pos); } break; } return true; } + + // endregion modes } //------------------------------------------------------------------------ @@ -808,1004 +1108,3 @@ function Doku_Handler_Parse_Media($match) { 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/inc/parser/lexer.php b/inc/parser/lexer.php deleted file mode 100644 index ba6a65397..000000000 --- a/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/inc/parser/metadata.php b/inc/parser/metadata.php index f9e05bd81..5af7b0215 100644 --- a/inc/parser/metadata.php +++ b/inc/parser/metadata.php @@ -1,22 +1,5 @@ <?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 @@ -24,6 +7,8 @@ if(!defined('DOKU_TAB')) { * $persistent. * * Some simplified rendering to $doc is done to gather the page's (text-only) abstract. + * + * @author Esther Brunner <wikidesign@gmail.com> */ class Doku_Renderer_metadata extends Doku_Renderer { /** the approximate byte lenght to capture for the abstract */ @@ -61,7 +46,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @return string always 'metadata' */ - function getFormat() { + public function getFormat() { return 'metadata'; } @@ -70,7 +55,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * Sets up some of the persistent info about the page if it doesn't exist, yet. */ - function document_start() { + public function document_start() { global $ID; $this->headers = array(); @@ -94,7 +79,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * Stores collected data in the metadata */ - function document_end() { + public function document_end() { global $ID; // store internal info in metadata (notoc,nocache) @@ -141,7 +126,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $text the text to display * @param int $level the nesting level */ - function toc_additem($id, $text, $level) { + public function toc_additem($id, $text, $level) { global $conf; //only add items within configured levels @@ -164,7 +149,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param int $level header level * @param int $pos byte position in the original source */ - function header($text, $level, $pos) { + public function header($text, $level, $pos) { if(!isset($this->meta['title'])) $this->meta['title'] = $text; // add the header to the TOC @@ -178,28 +163,28 @@ class Doku_Renderer_metadata extends Doku_Renderer { /** * Open a paragraph */ - function p_open() { + public function p_open() { $this->cdata(DOKU_LF); } /** * Close a paragraph */ - function p_close() { + public function p_close() { $this->cdata(DOKU_LF); } /** * Create a line break */ - function linebreak() { + public function linebreak() { $this->cdata(DOKU_LF); } /** * Create a horizontal line */ - function hr() { + public function hr() { $this->cdata(DOKU_LF.'----------'.DOKU_LF); } @@ -212,7 +197,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @author Andreas Gohr <andi@splitbrain.org> */ - function footnote_open() { + public function footnote_open() { if($this->capture) { // move current content to store // this is required to ensure safe behaviour of plugins accessed within footnotes @@ -232,7 +217,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @author Andreas Gohr */ - function footnote_close() { + public function footnote_close() { if($this->capture) { // re-enable capturing $this->capturing = true; @@ -245,14 +230,14 @@ class Doku_Renderer_metadata extends Doku_Renderer { /** * Open an unordered list */ - function listu_open() { + public function listu_open() { $this->cdata(DOKU_LF); } /** * Open an ordered list */ - function listo_open() { + public function listo_open() { $this->cdata(DOKU_LF); } @@ -262,14 +247,14 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param int $level the nesting level * @param bool $node true when a node; false when a leaf */ - function listitem_open($level,$node=false) { + public function listitem_open($level,$node=false) { $this->cdata(str_repeat(DOKU_TAB, $level).'* '); } /** * Close a list item */ - function listitem_close() { + public function listitem_close() { $this->cdata(DOKU_LF); } @@ -278,21 +263,21 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @param string $text */ - function preformatted($text) { + public function preformatted($text) { $this->cdata($text); } /** * Start a block quote */ - function quote_open() { + public function quote_open() { $this->cdata(DOKU_LF.DOKU_TAB.'"'); } /** * Stop a block quote */ - function quote_close() { + public function quote_close() { $this->cdata('"'.DOKU_LF); } @@ -303,7 +288,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $lang programming language to use for syntax highlighting * @param string $file file path label */ - function file($text, $lang = null, $file = null) { + public function file($text, $lang = null, $file = null) { $this->cdata(DOKU_LF.$text.DOKU_LF); } @@ -314,7 +299,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $language programming language to use for syntax highlighting * @param string $file file path label */ - function code($text, $language = null, $file = null) { + public function code($text, $language = null, $file = null) { $this->cdata(DOKU_LF.$text.DOKU_LF); } @@ -325,7 +310,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @param string $acronym */ - function acronym($acronym) { + public function acronym($acronym) { $this->cdata($acronym); } @@ -336,7 +321,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @param string $smiley */ - function smiley($smiley) { + public function smiley($smiley) { $this->cdata($smiley); } @@ -349,7 +334,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @param string $entity */ - function entity($entity) { + public function entity($entity) { $this->cdata($entity); } @@ -361,14 +346,14 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string|int $x first value * @param string|int $y second value */ - function multiplyentity($x, $y) { + public function multiplyentity($x, $y) { $this->cdata($x.'×'.$y); } /** * Render an opening single quote char (language specific) */ - function singlequoteopening() { + public function singlequoteopening() { global $lang; $this->cdata($lang['singlequoteopening']); } @@ -376,7 +361,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { /** * Render a closing single quote char (language specific) */ - function singlequoteclosing() { + public function singlequoteclosing() { global $lang; $this->cdata($lang['singlequoteclosing']); } @@ -384,7 +369,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { /** * Render an apostrophe char (language specific) */ - function apostrophe() { + public function apostrophe() { global $lang; $this->cdata($lang['apostrophe']); } @@ -392,7 +377,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { /** * Render an opening double quote char (language specific) */ - function doublequoteopening() { + public function doublequoteopening() { global $lang; $this->cdata($lang['doublequoteopening']); } @@ -400,7 +385,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { /** * Render an closinging double quote char (language specific) */ - function doublequoteclosing() { + public function doublequoteclosing() { global $lang; $this->cdata($lang['doublequoteclosing']); } @@ -411,7 +396,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $link The link name * @see http://en.wikipedia.org/wiki/CamelCase */ - function camelcaselink($link) { + public function camelcaselink($link) { $this->internallink($link, $link); } @@ -421,7 +406,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $hash hash link identifier * @param string $name name for the link */ - function locallink($hash, $name = null) { + public function locallink($hash, $name = null) { if(is_array($name)) { $this->_firstimage($name['src']); if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); @@ -434,7 +419,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @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) { + public function internallink($id, $name = null) { global $ID; if(is_array($name)) { @@ -471,7 +456,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @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) { + public function externallink($url, $name = null) { if(is_array($name)) { $this->_firstimage($name['src']); if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); @@ -492,7 +477,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @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) { + public function interwikilink($match, $name, $wikiName, $wikiUri) { if(is_array($name)) { $this->_firstimage($name['src']); if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); @@ -511,7 +496,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $url the link * @param string|array $name name for the link, array for media file */ - function windowssharelink($url, $name = null) { + public function windowssharelink($url, $name = null) { if(is_array($name)) { $this->_firstimage($name['src']); if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); @@ -531,7 +516,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $address Email-Address * @param string|array $name name for the link, array for media file */ - function emaillink($address, $name = null) { + public function emaillink($address, $name = null) { if(is_array($name)) { $this->_firstimage($name['src']); if($name['type'] == 'internalmedia') $this->_recordMediaUsage($name['src']); @@ -554,7 +539,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $cache cache|recache|nocache * @param string $linking linkonly|detail|nolink */ - function internalmedia($src, $title = null, $align = null, $width = null, + public 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); @@ -572,7 +557,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $cache cache|recache|nocache * @param string $linking linkonly|detail|nolink */ - function externalmedia($src, $title = null, $align = null, $width = null, + public 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); @@ -584,7 +569,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param string $url URL of the feed * @param array $params Finetuning of the output */ - function rss($url, $params) { + public function rss($url, $params) { $this->meta['relation']['haspart'][$url] = true; $this->meta['date']['valid']['age'] = @@ -605,7 +590,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @return mixed|string */ - function _simpleTitle($name) { + public function _simpleTitle($name) { global $conf; if(is_array($name)) return ''; @@ -622,23 +607,6 @@ class Doku_Renderer_metadata extends Doku_Renderer { } /** - * 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> @@ -647,7 +615,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * @param null|string $id linked page id (used to extract title from first heading) * @return string title text */ - function _getLinkTitle($title, $default, $id = null) { + public function _getLinkTitle($title, $default, $id = null) { if(is_array($title)) { if($title['title']) { return '['.$title['title'].']'; @@ -670,7 +638,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @param string $src image URL or ID */ - function _firstimage($src) { + protected function _firstimage($src) { if($this->firstimage) return; global $ID; @@ -688,7 +656,7 @@ class Doku_Renderer_metadata extends Doku_Renderer { * * @param string $src media ID */ - function _recordMediaUsage($src) { + protected function _recordMediaUsage($src) { global $ID; list ($src) = explode('#', $src, 2); diff --git a/inc/parser/parser.php b/inc/parser/parser.php index 8cff2b8be..d9fc5fb8f 100644 --- a/inc/parser/parser.php +++ b/inc/parser/parser.php @@ -1,8 +1,4 @@ <?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 @@ -13,1022 +9,49 @@ $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'), + 'container' => array('listblock', 'table', 'quote', 'hr'), // some mode are allowed inside the base mode only - 'baseonly' => array('header'), + 'baseonly' => array('header'), // modes for styling text -- footnote behaves similar to styling - 'formatting' => array('strong', 'emphasis', 'underline', 'monospace', - 'subscript', 'superscript', 'deleted', 'footnote'), + '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'), + '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'), + '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'), + 'disabled' => array('unformatted'), // used to mark paragraph boundaries - 'paragraphs' => array('eol') + '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 + * Class Doku_Parser * - * Adds additional functions to syntax plugins + * @deprecated 2018-05-04 */ -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 { +class Doku_Parser extends \dokuwiki\Parsing\Parser { - 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; + /** @inheritdoc */ + public function __construct(Doku_Handler $handler) { + dbg_deprecated(\dokuwiki\Parsing\Parser::class); + parent::__construct($handler); } } - -//------------------------------------------------------------------- -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/inc/parser/renderer.php b/inc/parser/renderer.php index 83b51d4b1..eb4d658be 100644 --- a/inc/parser/renderer.php +++ b/inc/parser/renderer.php @@ -5,7 +5,6 @@ * @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 @@ -24,7 +23,7 @@ define('PREG_PATTERN_VALID_LANGUAGE', '#[^a-zA-Z0-9\-_]#'); * $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 { +abstract 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? @@ -40,6 +39,9 @@ class Doku_Renderer extends DokuWiki_Plugin { /** @var array contains the interwiki configuration, set in p_render() */ public $interwiki = array(); + /** @var array the list of headers used to create unique link ids */ + protected $headers = array(); + /** * @var string the rendered document, this will be cached after the renderer ran through */ @@ -51,7 +53,8 @@ class Doku_Renderer extends DokuWiki_Plugin { * 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() { + public function reset(){ + $this->headers = array(); } /** @@ -62,7 +65,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @return bool false if the plugin has to be instantiated */ - function isSingleton() { + public function isSingleton() { return false; } @@ -73,15 +76,12 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @return string */ - function getFormat() { - trigger_error('getFormat() not implemented in '.get_class($this), E_USER_WARNING); - return ''; - } + abstract public function getFormat(); /** * Disable caching of this renderer's output */ - function nocache() { + public function nocache() { $this->info['cache'] = false; } @@ -90,7 +90,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * This might not be used for certain sub renderer */ - function notoc() { + public function notoc() { $this->info['toc'] = false; } @@ -104,7 +104,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $state matched state if any * @param string $match raw matched syntax */ - function plugin($name, $data, $state = '', $match = '') { + public function plugin($name, $data, $state = '', $match = '') { /** @var DokuWiki_Syntax_Plugin $plugin */ $plugin = plugin_load('syntax', $name); if($plugin != null) { @@ -118,7 +118,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param array $instructions */ - function nest($instructions) { + public function nest($instructions) { foreach($instructions as $instruction) { // execute the callback against ourself if(method_exists($this, $instruction[0])) { @@ -133,7 +133,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * 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() { + public function nest_close() { } #region Syntax modes - sub classes will need to implement them to fill $doc @@ -141,13 +141,13 @@ class Doku_Renderer extends DokuWiki_Plugin { /** * Initialize the document */ - function document_start() { + public function document_start() { } /** * Finalize the document */ - function document_end() { + public function document_end() { } /** @@ -155,7 +155,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @return string */ - function render_TOC() { + public function render_TOC() { return ''; } @@ -166,7 +166,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $text the text to display * @param int $level the nesting level */ - function toc_additem($id, $text, $level) { + public function toc_additem($id, $text, $level) { } /** @@ -176,7 +176,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param int $level header level * @param int $pos byte position in the original source */ - function header($text, $level, $pos) { + public function header($text, $level, $pos) { } /** @@ -184,13 +184,13 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param int $level section level (as determined by the previous header) */ - function section_open($level) { + public function section_open($level) { } /** * Close the current section */ - function section_close() { + public function section_close() { } /** @@ -198,151 +198,151 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $text */ - function cdata($text) { + public function cdata($text) { } /** * Open a paragraph */ - function p_open() { + public function p_open() { } /** * Close a paragraph */ - function p_close() { + public function p_close() { } /** * Create a line break */ - function linebreak() { + public function linebreak() { } /** * Create a horizontal line */ - function hr() { + public function hr() { } /** * Start strong (bold) formatting */ - function strong_open() { + public function strong_open() { } /** * Stop strong (bold) formatting */ - function strong_close() { + public function strong_close() { } /** * Start emphasis (italics) formatting */ - function emphasis_open() { + public function emphasis_open() { } /** * Stop emphasis (italics) formatting */ - function emphasis_close() { + public function emphasis_close() { } /** * Start underline formatting */ - function underline_open() { + public function underline_open() { } /** * Stop underline formatting */ - function underline_close() { + public function underline_close() { } /** * Start monospace formatting */ - function monospace_open() { + public function monospace_open() { } /** * Stop monospace formatting */ - function monospace_close() { + public function monospace_close() { } /** * Start a subscript */ - function subscript_open() { + public function subscript_open() { } /** * Stop a subscript */ - function subscript_close() { + public function subscript_close() { } /** * Start a superscript */ - function superscript_open() { + public function superscript_open() { } /** * Stop a superscript */ - function superscript_close() { + public function superscript_close() { } /** * Start deleted (strike-through) formatting */ - function deleted_open() { + public function deleted_open() { } /** * Stop deleted (strike-through) formatting */ - function deleted_close() { + public function deleted_close() { } /** * Start a footnote */ - function footnote_open() { + public function footnote_open() { } /** * Stop a footnote */ - function footnote_close() { + public function footnote_close() { } /** * Open an unordered list */ - function listu_open() { + public function listu_open() { } /** * Close an unordered list */ - function listu_close() { + public function listu_close() { } /** * Open an ordered list */ - function listo_open() { + public function listo_open() { } /** * Close an ordered list */ - function listo_close() { + public function listo_close() { } /** @@ -351,25 +351,25 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param int $level the nesting level * @param bool $node true when a node; false when a leaf */ - function listitem_open($level,$node=false) { + public function listitem_open($level,$node=false) { } /** * Close a list item */ - function listitem_close() { + public function listitem_close() { } /** * Start the content of a list item */ - function listcontent_open() { + public function listcontent_open() { } /** * Stop the content of a list item */ - function listcontent_close() { + public function listcontent_close() { } /** @@ -379,7 +379,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $text */ - function unformatted($text) { + public function unformatted($text) { $this->cdata($text); } @@ -391,7 +391,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $text The PHP code */ - function php($text) { + public function php($text) { } /** @@ -402,7 +402,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $text The PHP code */ - function phpblock($text) { + public function phpblock($text) { } /** @@ -412,7 +412,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $text The HTML */ - function html($text) { + public function html($text) { } /** @@ -422,7 +422,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $text The HTML */ - function htmlblock($text) { + public function htmlblock($text) { } /** @@ -430,19 +430,19 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $text */ - function preformatted($text) { + public function preformatted($text) { } /** * Start a block quote */ - function quote_open() { + public function quote_open() { } /** * Stop a block quote */ - function quote_close() { + public function quote_close() { } /** @@ -452,7 +452,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $lang programming language to use for syntax highlighting * @param string $file file path label */ - function file($text, $lang = null, $file = null) { + public function file($text, $lang = null, $file = null) { } /** @@ -462,7 +462,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $lang programming language to use for syntax highlighting * @param string $file file path label */ - function code($text, $lang = null, $file = null) { + public function code($text, $lang = null, $file = null) { } /** @@ -472,7 +472,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $acronym */ - function acronym($acronym) { + public function acronym($acronym) { } /** @@ -482,7 +482,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $smiley */ - function smiley($smiley) { + public function smiley($smiley) { } /** @@ -494,7 +494,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param string $entity */ - function entity($entity) { + public function entity($entity) { } /** @@ -505,37 +505,37 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string|int $x first value * @param string|int $y second value */ - function multiplyentity($x, $y) { + public function multiplyentity($x, $y) { } /** * Render an opening single quote char (language specific) */ - function singlequoteopening() { + public function singlequoteopening() { } /** * Render a closing single quote char (language specific) */ - function singlequoteclosing() { + public function singlequoteclosing() { } /** * Render an apostrophe char (language specific) */ - function apostrophe() { + public function apostrophe() { } /** * Render an opening double quote char (language specific) */ - function doublequoteopening() { + public function doublequoteopening() { } /** * Render an closinging double quote char (language specific) */ - function doublequoteclosing() { + public function doublequoteclosing() { } /** @@ -544,7 +544,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $link The link name * @see http://en.wikipedia.org/wiki/CamelCase */ - function camelcaselink($link) { + public function camelcaselink($link) { } /** @@ -553,7 +553,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $hash hash link identifier * @param string $name name for the link */ - function locallink($hash, $name = null) { + public function locallink($hash, $name = null) { } /** @@ -562,7 +562,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @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) { + public function internallink($link, $title = null) { } /** @@ -571,7 +571,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $link full URL with scheme * @param string|array $title name for the link, array for media file */ - function externallink($link, $title = null) { + public function externallink($link, $title = null) { } /** @@ -580,7 +580,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $url URL of the feed * @param array $params Finetuning of the output */ - function rss($url, $params) { + public function rss($url, $params) { } /** @@ -593,7 +593,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @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) { + public function interwikilink($link, $title, $wikiName, $wikiUri) { } /** @@ -602,7 +602,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $link the link * @param string|array $title name for the link, array for media file */ - function filelink($link, $title = null) { + public function filelink($link, $title = null) { } /** @@ -611,7 +611,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $link the link * @param string|array $title name for the link, array for media file */ - function windowssharelink($link, $title = null) { + public function windowssharelink($link, $title = null) { } /** @@ -622,7 +622,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $address Email-Address * @param string|array $name name for the link, array for media file */ - function emaillink($address, $name = null) { + public function emaillink($address, $name = null) { } /** @@ -636,7 +636,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $cache cache|recache|nocache * @param string $linking linkonly|detail|nolink */ - function internalmedia($src, $title = null, $align = null, $width = null, + public function internalmedia($src, $title = null, $align = null, $width = null, $height = null, $cache = null, $linking = null) { } @@ -651,7 +651,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $cache cache|recache|nocache * @param string $linking linkonly|detail|nolink */ - function externalmedia($src, $title = null, $align = null, $width = null, + public function externalmedia($src, $title = null, $align = null, $width = null, $height = null, $cache = null, $linking = null) { } @@ -665,7 +665,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param int $height height of media in pixel * @param string $cache cache|recache|nocache */ - function internalmedialink($src, $title = null, $align = null, + public function internalmedialink($src, $title = null, $align = null, $width = null, $height = null, $cache = null) { } @@ -679,7 +679,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param int $height height of media in pixel * @param string $cache cache|recache|nocache */ - function externalmedialink($src, $title = null, $align = null, + public function externalmedialink($src, $title = null, $align = null, $width = null, $height = null, $cache = null) { } @@ -690,7 +690,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param int $numrows NOT IMPLEMENTED * @param int $pos byte position in the original source */ - function table_open($maxcols = null, $numrows = null, $pos = null) { + public function table_open($maxcols = null, $numrows = null, $pos = null) { } /** @@ -698,55 +698,55 @@ class Doku_Renderer extends DokuWiki_Plugin { * * @param int $pos byte position in the original source */ - function table_close($pos = null) { + public function table_close($pos = null) { } /** * Open a table header */ - function tablethead_open() { + public function tablethead_open() { } /** * Close a table header */ - function tablethead_close() { + public function tablethead_close() { } /** * Open a table body */ - function tabletbody_open() { + public function tabletbody_open() { } /** * Close a table body */ - function tabletbody_close() { + public function tabletbody_close() { } /** * Open a table footer */ - function tabletfoot_open() { + public function tabletfoot_open() { } /** * Close a table footer */ - function tabletfoot_close() { + public function tabletfoot_close() { } /** * Open a table row */ - function tablerow_open() { + public function tablerow_open() { } /** * Close a table row */ - function tablerow_close() { + public function tablerow_close() { } /** @@ -756,13 +756,13 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $align left|center|right * @param int $rowspan */ - function tableheader_open($colspan = 1, $align = null, $rowspan = 1) { + public function tableheader_open($colspan = 1, $align = null, $rowspan = 1) { } /** * Close a table header cell */ - function tableheader_close() { + public function tableheader_close() { } /** @@ -772,13 +772,13 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $align left|center|right * @param int $rowspan */ - function tablecell_open($colspan = 1, $align = null, $rowspan = 1) { + public function tablecell_open($colspan = 1, $align = null, $rowspan = 1) { } /** * Close a table cell */ - function tablecell_close() { + public function tablecell_close() { } #endregion @@ -786,6 +786,23 @@ class Doku_Renderer extends DokuWiki_Plugin { #region util functions, you probably won't need to reimplement them /** + * 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 + */ + public function _headerToLink($title, $create = false) { + if($create) { + return sectionID($title, $this->headers); + } else { + $check = false; + return sectionID($title, $check); + } + } + + /** * Removes any Namespace from the given name but keeps * casing and special chars * @@ -794,7 +811,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param string $name * @return string */ - function _simpleTitle($name) { + protected function _simpleTitle($name) { global $conf; //if there is a hash we use the ancor name only @@ -818,7 +835,7 @@ class Doku_Renderer extends DokuWiki_Plugin { * @param null|bool $exists reference which returns if an internal page exists * @return string interwikilink */ - function _resolveInterWiki(&$shortcut, $reference, &$exists = null) { + public function _resolveInterWiki(&$shortcut, $reference, &$exists = null) { //get interwiki URL if(isset($this->interwiki[$shortcut])) { $url = $this->interwiki[$shortcut]; diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php index 34a7d3e64..1b4387d2b 100644 --- a/inc/parser/xhtml.php +++ b/inc/parser/xhtml.php @@ -2,25 +2,11 @@ /** * Renderer for XHTML output * + * This is DokuWiki's main renderer used to display page content in the wiki + * * @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 */ @@ -28,14 +14,13 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** @var array A stack of section edit data */ protected $sectionedits = array(); - var $date_at = ''; // link pages and media against this revision + + /** @var string|int link pages and media against this revision */ + public $date_at = ''; /** @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(); @@ -122,23 +107,22 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @return string always 'xhtml' */ - function getFormat() { + public function getFormat() { return 'xhtml'; } /** * Initialize the document */ - function document_start() { + public function document_start() { //reset some internals $this->toc = array(); - $this->headers = array(); } /** * Finalize the document */ - function document_end() { + public function document_end() { // Finish open section edits. while(count($this->sectionedits) > 0) { if($this->sectionedits[count($this->sectionedits) - 1]['start'] <= 1) { @@ -183,7 +167,11 @@ class Doku_Renderer_xhtml extends Doku_Renderer { // Prepare the TOC global $conf; - if($this->info['toc'] && is_array($this->toc) && $conf['tocminheads'] && count($this->toc) >= $conf['tocminheads']) { + if( + $this->info['toc'] && + is_array($this->toc) && + $conf['tocminheads'] && count($this->toc) >= $conf['tocminheads'] + ) { global $TOC; $TOC = $this->toc; } @@ -199,7 +187,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param string $text the text to display * @param int $level the nesting level */ - function toc_additem($id, $text, $level) { + public function toc_additem($id, $text, $level) { global $conf; //handle TOC @@ -215,7 +203,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param int $level header level * @param int $pos byte position in the original source */ - function header($text, $level, $pos) { + public function header($text, $level, $pos) { global $conf; if(blank($text)) return; //skip empty headlines @@ -261,14 +249,14 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param int $level section level (as determined by the previous header) */ - function section_open($level) { + public function section_open($level) { $this->doc .= '<div class="level'.$level.'">'.DOKU_LF; } /** * Close the current section */ - function section_close() { + public function section_close() { $this->doc .= DOKU_LF.'</div>'.DOKU_LF; } @@ -277,133 +265,133 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param $text */ - function cdata($text) { + public function cdata($text) { $this->doc .= $this->_xmlEntities($text); } /** * Open a paragraph */ - function p_open() { + public function p_open() { $this->doc .= DOKU_LF.'<p>'.DOKU_LF; } /** * Close a paragraph */ - function p_close() { + public function p_close() { $this->doc .= DOKU_LF.'</p>'.DOKU_LF; } /** * Create a line break */ - function linebreak() { + public function linebreak() { $this->doc .= '<br/>'.DOKU_LF; } /** * Create a horizontal line */ - function hr() { + public function hr() { $this->doc .= '<hr />'.DOKU_LF; } /** * Start strong (bold) formatting */ - function strong_open() { + public function strong_open() { $this->doc .= '<strong>'; } /** * Stop strong (bold) formatting */ - function strong_close() { + public function strong_close() { $this->doc .= '</strong>'; } /** * Start emphasis (italics) formatting */ - function emphasis_open() { + public function emphasis_open() { $this->doc .= '<em>'; } /** * Stop emphasis (italics) formatting */ - function emphasis_close() { + public function emphasis_close() { $this->doc .= '</em>'; } /** * Start underline formatting */ - function underline_open() { + public function underline_open() { $this->doc .= '<em class="u">'; } /** * Stop underline formatting */ - function underline_close() { + public function underline_close() { $this->doc .= '</em>'; } /** * Start monospace formatting */ - function monospace_open() { + public function monospace_open() { $this->doc .= '<code>'; } /** * Stop monospace formatting */ - function monospace_close() { + public function monospace_close() { $this->doc .= '</code>'; } /** * Start a subscript */ - function subscript_open() { + public function subscript_open() { $this->doc .= '<sub>'; } /** * Stop a subscript */ - function subscript_close() { + public function subscript_close() { $this->doc .= '</sub>'; } /** * Start a superscript */ - function superscript_open() { + public function superscript_open() { $this->doc .= '<sup>'; } /** * Stop a superscript */ - function superscript_close() { + public function superscript_close() { $this->doc .= '</sup>'; } /** * Start deleted (strike-through) formatting */ - function deleted_open() { + public function deleted_open() { $this->doc .= '<del>'; } /** * Stop deleted (strike-through) formatting */ - function deleted_close() { + public function deleted_close() { $this->doc .= '</del>'; } @@ -416,7 +404,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @author Andreas Gohr <andi@splitbrain.org> */ - function footnote_open() { + public function footnote_open() { // move current content to store and record footnote $this->store = $this->doc; @@ -431,7 +419,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @author Andreas Gohr */ - function footnote_close() { + public 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) @@ -462,7 +450,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input */ - function listu_open($classes = null) { + public function listu_open($classes = null) { $class = ''; if($classes !== null) { if(is_array($classes)) $classes = join(' ', $classes); @@ -474,7 +462,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Close an unordered list */ - function listu_close() { + public function listu_close() { $this->doc .= '</ul>'.DOKU_LF; } @@ -483,7 +471,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input */ - function listo_open($classes = null) { + public function listo_open($classes = null) { $class = ''; if($classes !== null) { if(is_array($classes)) $classes = join(' ', $classes); @@ -495,7 +483,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Close an ordered list */ - function listo_close() { + public function listo_close() { $this->doc .= '</ol>'.DOKU_LF; } @@ -505,7 +493,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param int $level the nesting level * @param bool $node true when a node; false when a leaf */ - function listitem_open($level, $node=false) { + public function listitem_open($level, $node=false) { $branching = $node ? ' node' : ''; $this->doc .= '<li class="level'.$level.$branching.'">'; } @@ -513,21 +501,21 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Close a list item */ - function listitem_close() { + public function listitem_close() { $this->doc .= '</li>'.DOKU_LF; } /** * Start the content of a list item */ - function listcontent_open() { + public function listcontent_open() { $this->doc .= '<div class="li">'; } /** * Stop the content of a list item */ - function listcontent_close() { + public function listcontent_close() { $this->doc .= '</div>'.DOKU_LF; } @@ -538,7 +526,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string $text */ - function unformatted($text) { + public function unformatted($text) { $this->doc .= $this->_xmlEntities($text); } @@ -550,7 +538,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @author Andreas Gohr <andi@splitbrain.org> */ - function php($text, $wrapper = 'code') { + public function php($text, $wrapper = 'code') { global $conf; if($conf['phpok']) { @@ -571,7 +559,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string $text The PHP code */ - function phpblock($text) { + public function phpblock($text) { $this->php($text, 'pre'); } @@ -583,7 +571,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @author Andreas Gohr <andi@splitbrain.org> */ - function html($text, $wrapper = 'code') { + public function html($text, $wrapper = 'code') { global $conf; if($conf['htmlok']) { @@ -600,21 +588,21 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string $text The HTML */ - function htmlblock($text) { + public function htmlblock($text) { $this->html($text, 'pre'); } /** * Start a block quote */ - function quote_open() { + public function quote_open() { $this->doc .= '<blockquote><div class="no">'.DOKU_LF; } /** * Stop a block quote */ - function quote_close() { + public function quote_close() { $this->doc .= '</div></blockquote>'.DOKU_LF; } @@ -623,7 +611,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string $text */ - function preformatted($text) { + public function preformatted($text) { $this->doc .= '<pre class="code">'.trim($this->_xmlEntities($text), "\n\r").'</pre>'.DOKU_LF; } @@ -635,7 +623,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param string $filename file path label * @param array $options assoziative array with additional geshi options */ - function file($text, $language = null, $filename = null, $options=null) { + public function file($text, $language = null, $filename = null, $options=null) { $this->_highlight('file', $text, $language, $filename, $options); } @@ -647,7 +635,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param string $filename file path label * @param array $options assoziative array with additional geshi options */ - function code($text, $language = null, $filename = null, $options=null) { + public function code($text, $language = null, $filename = null, $options=null) { $this->_highlight('code', $text, $language, $filename, $options); } @@ -661,7 +649,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public function _highlight($type, $text, $language = null, $filename = null, $options = null) { global $ID; global $lang; global $INPUT; @@ -679,7 +667,12 @@ class Doku_Renderer_xhtml extends Doku_Renderer { $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 .= '<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>'; } @@ -697,7 +690,9 @@ class Doku_Renderer_xhtml extends Doku_Renderer { $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; + $this->doc .= "<pre class=\"$class $language\">" . + p_xhtml_cached_geshi($text, $language, '', $options) . + '</pre>' . DOKU_LF; } if($filename) { @@ -714,7 +709,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string $acronym */ - function acronym($acronym) { + public function acronym($acronym) { if(array_key_exists($acronym, $this->acronyms)) { @@ -735,7 +730,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string $smiley */ - function smiley($smiley) { + public 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="'. @@ -754,7 +749,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string $entity */ - function entity($entity) { + public function entity($entity) { if(array_key_exists($entity, $this->entities)) { $this->doc .= $this->entities[$entity]; } else { @@ -770,14 +765,14 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param string|int $x first value * @param string|int $y second value */ - function multiplyentity($x, $y) { + public function multiplyentity($x, $y) { $this->doc .= "$x×$y"; } /** * Render an opening single quote char (language specific) */ - function singlequoteopening() { + public function singlequoteopening() { global $lang; $this->doc .= $lang['singlequoteopening']; } @@ -785,7 +780,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Render a closing single quote char (language specific) */ - function singlequoteclosing() { + public function singlequoteclosing() { global $lang; $this->doc .= $lang['singlequoteclosing']; } @@ -793,7 +788,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Render an apostrophe char (language specific) */ - function apostrophe() { + public function apostrophe() { global $lang; $this->doc .= $lang['apostrophe']; } @@ -801,7 +796,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Render an opening double quote char (language specific) */ - function doublequoteopening() { + public function doublequoteopening() { global $lang; $this->doc .= $lang['doublequoteopening']; } @@ -809,7 +804,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Render an closinging double quote char (language specific) */ - function doublequoteclosing() { + public function doublequoteclosing() { global $lang; $this->doc .= $lang['doublequoteclosing']; } @@ -823,7 +818,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @see http://en.wikipedia.org/wiki/CamelCase */ - function camelcaselink($link, $returnonly = false) { + public function camelcaselink($link, $returnonly = false) { if($returnonly) { return $this->internallink($link, $link, null, true); } else { @@ -839,7 +834,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public function locallink($hash, $name = null, $returnonly = false) { global $ID; $name = $this->_getLinkTitle($name, $hash, $isImage); $hash = $this->_headerToLink($hash); @@ -870,7 +865,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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') { + public function internallink($id, $name = null, $search = null, $returnonly = false, $linktype = 'content') { global $conf; global $ID; global $INFO; @@ -961,7 +956,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public function externallink($url, $name = null, $returnonly = false) { global $conf; $name = $this->_getLinkTitle($name, $url, $isImage); @@ -1025,7 +1020,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public function interwikilink($match, $name, $wikiName, $wikiUri, $returnonly = false) { global $conf; $link = array(); @@ -1080,7 +1075,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public function windowssharelink($url, $name = null, $returnonly = false) { global $conf; //simple setup @@ -1120,7 +1115,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public function emaillink($address, $name = null, $returnonly = false) { global $conf; //simple setup $link = array(); @@ -1172,7 +1167,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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, + public function internalmedia($src, $title = null, $align = null, $width = null, $height = null, $cache = null, $linking = null, $return = false) { global $ID; if (strpos($src, '#') !== false) { @@ -1186,7 +1181,15 @@ class Doku_Renderer_xhtml extends Doku_Renderer { 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')); + $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; @@ -1194,7 +1197,15 @@ class Doku_Renderer_xhtml extends Doku_Renderer { // 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); + $link['url'] = ml( + $src, + array( + 'id' => $ID, + 'cache' => $cache, + 'rev' => $this->_getLastMediaRevisionAt($src) + ), + true + ); if($exists) $link['title'] .= ' ('.filesize_h(filesize(mediaFN($src))).')'; } @@ -1228,7 +1239,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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, + public 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); @@ -1275,7 +1286,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @author Andreas Gohr <andi@splitbrain.org> */ - function rss($url, $params) { + public function rss($url, $params) { global $lang; global $conf; @@ -1367,7 +1378,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public 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'; @@ -1392,7 +1403,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param int $pos byte position in the original source */ - function table_close($pos = null) { + public function table_close($pos = null) { $this->doc .= '</table></div>'.DOKU_LF; if($pos !== null) { $this->finishSectionEdit($pos); @@ -1402,42 +1413,42 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Open a table header */ - function tablethead_open() { + public function tablethead_open() { $this->doc .= DOKU_TAB.'<thead>'.DOKU_LF; } /** * Close a table header */ - function tablethead_close() { + public function tablethead_close() { $this->doc .= DOKU_TAB.'</thead>'.DOKU_LF; } /** * Open a table body */ - function tabletbody_open() { + public function tabletbody_open() { $this->doc .= DOKU_TAB.'<tbody>'.DOKU_LF; } /** * Close a table body */ - function tabletbody_close() { + public function tabletbody_close() { $this->doc .= DOKU_TAB.'</tbody>'.DOKU_LF; } /** * Open a table footer */ - function tabletfoot_open() { + public function tabletfoot_open() { $this->doc .= DOKU_TAB.'<tfoot>'.DOKU_LF; } /** * Close a table footer */ - function tabletfoot_close() { + public function tabletfoot_close() { $this->doc .= DOKU_TAB.'</tfoot>'.DOKU_LF; } @@ -1446,7 +1457,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @param string|string[] $classes css classes - have to be valid, do not pass unfiltered user input */ - function tablerow_open($classes = null) { + public function tablerow_open($classes = null) { // initialize the cell counter used for classes $this->_counter['cell_counter'] = 0; $class = 'row'.$this->_counter['row_counter']++; @@ -1460,7 +1471,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Close a table row */ - function tablerow_close() { + public function tablerow_close() { $this->doc .= DOKU_LF.DOKU_TAB.'</tr>'.DOKU_LF; } @@ -1472,7 +1483,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public 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'; @@ -1496,7 +1507,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Close a table header cell */ - function tableheader_close() { + public function tableheader_close() { $this->doc .= '</th>'; } @@ -1508,7 +1519,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public 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'; @@ -1532,7 +1543,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { /** * Close a table cell */ - function tablecell_close() { + public function tablecell_close() { $this->doc .= '</td>'; } @@ -1542,7 +1553,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @return int The current header level */ - function getLastlevel() { + public function getLastlevel() { return $this->lastlevel; } @@ -1558,7 +1569,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * * @author Andreas Gohr <andi@splitbrain.org> */ - function _formatLink($link) { + public 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']); @@ -1601,7 +1612,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param bool $render should the media be embedded inline or just linked * @return string */ - function _media($src, $title = null, $align = null, $width = null, + public function _media($src, $title = null, $align = null, $width = null, $height = null, $cache = null, $render = true) { $ret = ''; @@ -1630,7 +1641,14 @@ class Doku_Renderer_xhtml extends Doku_Renderer { return $title; } //add image tag - $ret .= '<img src="'.ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache, 'rev'=>$this->_getLastMediaRevisionAt($src))).'"'; + $ret .= '<img src="' . ml( + $src, + array( + 'w' => $width, 'h' => $height, + 'cache' => $cache, + 'rev' => $this->_getLastMediaRevisionAt($src) + ) + ) . '"'; $ret .= ' class="media'.$align.'"'; if($title) { @@ -1711,26 +1729,11 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param $string * @return string */ - function _xmlEntities($string) { + public 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 @@ -1743,7 +1746,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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') { + public function _getLinkTitle($title, $default, &$isImage, $id = null, $linktype = 'content') { $isImage = false; if(is_array($title)) { $isImage = true; @@ -1768,7 +1771,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param array $img * @return string HTML img tag or similar */ - function _imageTitle($img) { + public function _imageTitle($img) { global $ID; // some fixes on $img['src'] @@ -1803,7 +1806,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @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) { + public function _getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render) { global $conf; $link = array(); @@ -1832,7 +1835,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param array $atts - additional attributes for the <video> tag * @return string */ - function _video($src, $width, $height, $atts = null) { + public function _video($src, $width, $height, $atts = null) { // prepare width and height if(is_null($atts)) $atts = array(); $atts['width'] = (int) $width; @@ -1880,7 +1883,16 @@ class Doku_Renderer_xhtml extends Doku_Renderer { $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); + $fallback .= $this->$linkType( + $file, + $title, + null, + null, + null, + $cache = null, + $linking = 'linkonly', + $return = true + ); } // output each track if any @@ -1906,7 +1918,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @param array $atts - additional attributes for the <audio> tag * @return string */ - function _audio($src, $atts = array()) { + public function _audio($src, $atts = array()) { $files = array(); $isExternal = media_isexternal($src); @@ -1938,7 +1950,16 @@ class Doku_Renderer_xhtml extends Doku_Renderer { $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); + $fallback .= $this->$linkType( + $file, + $title, + null, + null, + null, + $cache = null, + $linking = 'linkonly', + $return = true + ); } // finish @@ -1956,7 +1977,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer { * @access protected * @return string revision ('' for current) */ - function _getLastMediaRevisionAt($media_id){ + protected function _getLastMediaRevisionAt($media_id){ if(!$this->date_at || media_isexternal($media_id)) return ''; $pagelog = new MediaChangeLog($media_id); return $pagelog->getLastRevisionAt($this->date_at); diff --git a/inc/parser/xhtmlsummary.php b/inc/parser/xhtmlsummary.php index 867b71f6a..4641bf836 100644 --- a/inc/parser/xhtmlsummary.php +++ b/inc/parser/xhtmlsummary.php @@ -1,6 +1,4 @@ <?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) @@ -20,32 +18,25 @@ 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; + protected $sum_paragraphs = 0; + protected $sum_capture = true; + protected $sum_inSection = false; + protected $sum_summary = ''; + protected $sum_pageTitle = false; - function document_start() { + /** @inheritdoc */ + public function document_start() { $this->doc .= DOKU_LF.'<div>'.DOKU_LF; } - function document_end() { + /** @inheritdoc */ + public 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) { + /** @inheritdoc */ + public function header($text, $level, $pos) { if ( !$this->sum_pageTitle ) { $this->info['sum_pagetitle'] = $text; $this->sum_pageTitle = true; @@ -55,27 +46,31 @@ class Doku_Renderer_xhtmlsummary extends Doku_Renderer_xhtml { $this->doc .= "</h$level>".DOKU_LF; } - function section_open($level) { + /** @inheritdoc */ + public function section_open($level) { if ( $this->sum_capture ) { $this->sum_inSection = true; } } - function section_close() { + /** @inheritdoc */ + public function section_close() { if ( $this->sum_capture && $this->sum_inSection ) { $this->sum_summary .= $this->doc; $this->sum_capture = false; } } - function p_open() { + /** @inheritdoc */ + public function p_open() { if ( $this->sum_capture && $this->sum_paragraphs < 2 ) { $this->sum_paragraphs++; } parent :: p_open(); } - function p_close() { + /** @inheritdoc */ + public function p_close() { parent :: p_close(); if ( $this->sum_capture && $this->sum_paragraphs >= 2 ) { $this->sum_summary .= $this->doc; |