1<?php 2/** 3 * DokuWiki Plugin KaTeX (Syntax Component: protect) 4 * 5 * protect TeX expressions before DokuWiki trying to parse them. 6 * 7 * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html 8 * @author H.-H. PENG (Hsins) <hsinspeng@gmail.com> 9 * @author Mark Liffiton <liffiton@gmail.com> 10 */ 11 12// must be run within Dokuwiki 13if ( !defined( 'DOKU_INC' ) ) { 14 die(); 15} 16 17/** 18 * Class syntax_plugin_katex 19 */ 20class syntax_plugin_katex_protect extends DokuWiki_Syntax_Plugin 21{ 22 # We need to grab any math before dokuwiki tries to parse it. 23 # Once it's 'claimed' by this plugin (type: protected), it won't be altered. 24 25 # Set of environments that this plugin will protect from Dokuwiki parsing 26 # * is escaped to work in regexp below 27 private static $ENVIRONMENTS = array( 28 "math", 29 "displaymath", 30 "equation", 31 "equation\*", 32 "eqnarray", 33 "eqnarray\*", 34 "align", 35 "align\*", 36 "flalign", 37 "flalign\*", 38 "alignat", 39 "alignat\*", 40 "multline", 41 "multline\*", 42 "gather", 43 "gather\*", 44 ); 45 46 /** 47 * Syntax Type 48 * 49 * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 50 * 51 * @return string 52 */ 53 public function getType() 54 { 55 return 'protected'; 56 } 57 58 /** 59 * Sort for applying this mode 60 * 61 * @return int 62 */ 63 public function getSort() 64 { 65 return 65; 66 } 67 68 /** 69 * regexp patterns adapted from jsMath plugin: https://www.dokuwiki.org/plugin:jsmath 70 * 71 * @param string $mode 72 */ 73 public function connectTo( $mode ) 74 { 75 $this->Lexer->addEntryPattern( '(?<!\\\\)\$(?=[^\$][^\r\n]*?\$)', $mode, 'plugin_katex_protect' ); 76 $this->Lexer->addEntryPattern( '\$\$(?=.*?\$\$)', $mode, 'plugin_katex_protect' ); 77 $this->Lexer->addEntryPattern( '\\\\\((?=.*?\\\\\))', $mode, 'plugin_katex_protect' ); 78 $this->Lexer->addEntryPattern( '\\\\\[(?=.*?\\\\])', $mode, 'plugin_katex_protect' ); 79 foreach ( self::$ENVIRONMENTS as $env ) { 80 $this->Lexer->addEntryPattern( '\\\\begin{' . $env . '}(?=.*?\\\\end{' . $env . '})', $mode, 'plugin_katex_protect' ); 81 } 82 83 if ( $this->getConf( 'asciimath' ) ) { 84 // Protect the default AsciiMath delimiter 85 $this->Lexer->addEntryPattern( '`(?=.*?`)', $mode, 'plugin_katex_protect' ); 86 } 87 88 // Protect specified tags, if any 89 $conf_mathtags = $this->getConf( 'mathtags' ); 90 $mathtags = explode( ',', $conf_mathtags ); 91 foreach ( $mathtags as $tag ) { 92 $tag = trim( $tag ); 93 if ( $tag == "" ) {continue;} 94 $this->Lexer->addEntryPattern( '<' . $tag . '.*?>(?=.*?</' . $tag . '>)', $mode, 'plugin_katex_protect' ); 95 } 96 } 97 98 public function postConnect() 99 { 100 $this->Lexer->addExitPattern( '\$(?!\$)', 'plugin_katex_protect' ); 101 $this->Lexer->addExitPattern( '\\\\\)', 'plugin_katex_protect' ); 102 $this->Lexer->addExitPattern( '\\\\\]', 'plugin_katex_protect' ); 103 foreach ( self::$ENVIRONMENTS as $env ) { 104 $this->Lexer->addExitPattern( '\\\\end{' . $env . '}', 'plugin_katex_protect' ); 105 } 106 107 if ( $this->getConf( 'asciimath' ) ) { 108 // Protect the default AsciiMath delimiter 109 $this->Lexer->addExitPattern( '`', 'plugin_katex_protect' ); 110 } 111 112 // Protect specified tags, if any 113 $conf_mathtags = $this->getConf( 'mathtags' ); 114 $mathtags = explode( ',', $conf_mathtags ); 115 foreach ( $mathtags as $tag ) { 116 $tag = trim( $tag ); 117 if ( $tag == "" ) {continue;} 118 $this->Lexer->addExitPattern( '</' . $tag . '>', 'plugin_katex_protect' ); 119 } 120 } 121 122 /** 123 * Handler to prepare matched data for the rendering process 124 * 125 * This function can only pass data to render() via its return value - render() 126 * may be not be run during the object's current life. 127 * 128 * Usually you should only need the $match param. 129 * 130 * @param string $match The text matched by the patterns 131 * @param int $state The lexer state for the match 132 * @param int $pos The character position of the matched text 133 * @param Doku_Handler $handler The Doku_Handler object 134 * @return array Return an array with all data you want to use in render 135 */ 136 public function handle( $match, $state, $pos, Doku_Handler $handler ) 137 { 138 // Just pass it through... 139 return $match; 140 } 141 142 /** 143 * Handles the actual output creation. 144 * 145 * @param $mode string output format being rendered 146 * @param $renderer Doku_Renderer the current renderer object 147 * @param $data array data created by handler() 148 * @return boolean rendered correctly? 149 */ 150 public function render( $mode, Doku_Renderer $renderer, $data ) 151 { 152 if ( $mode == 'xhtml' || $mode == 'odt' ) { 153 /** @var Doku_Renderer_xhtml $renderer */ 154 155 // Just pass it through, but escape xml entities... 156 $renderer->doc .= $renderer->_xmlEntities( $data ); 157 return true; 158 } 159 if ( $mode == 'latexport' ) { 160 // Pass math expressions to latexport renderer 161 $renderer->mathjax_content( $data ); 162 return true; 163 } 164 165 // For all other modes, pass through unchanged. 166 $renderer->doc .= $data; 167 return true; 168 } 169} 170