1<?php 2/** 3 * DokuWiki Plugin caption (Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Till Biskup <till@till-biskup.de> 7 */ 8 9class syntax_plugin_caption_caption extends DokuWiki_Syntax_Plugin { 10 11 /** 12 * Array containing the types of environment supported by the plugin 13 */ 14 private $_types = array('figure','table','codeblock','fileblock'); 15 16 private $_type = ''; 17 private $_incaption = false; 18 19 private $_fignum = 1; 20 private $_tabnum = 1; 21 private $_codenum = 1; 22 private $_filenum = 1; 23 24 private $_label = ''; 25 26 private $_figlabels = array(); 27 private $_tablabels = array(); 28 private $_codelabels = array(); 29 private $_filelabels = array(); 30 31 /** 32 * return some info 33 */ 34 function getInfo(){ 35 return confToHash(dirname(__FILE__).'/../plugin.info.txt'); 36 } 37 38 public function getType() { 39 return 'container'; 40 } 41 42 public function getAllowedTypes() { 43 return array('formatting', 'substition', 'disabled', 'container', 'protected'); 44 } 45 46 public function getPType() { 47 return 'block'; 48 } 49 50 public function getSort() { 51 return 319; 52 } 53 54 55 public function connectTo($mode) { 56 $this->Lexer->addSpecialPattern('{{setcounter [a-z0-9=]+?}}',$mode,'plugin_caption_caption'); 57 $this->Lexer->addEntryPattern('<figure.*?>(?=.*</figure>)',$mode,'plugin_caption_caption'); 58 $this->Lexer->addEntryPattern('<table.*?>(?=.*</table>)',$mode,'plugin_caption_caption'); 59 $this->Lexer->addEntryPattern('<codeblock.*?>(?=.*</codeblock>)',$mode,'plugin_caption_caption'); 60 $this->Lexer->addEntryPattern('<fileblock.*?>(?=.*</fileblock>)',$mode,'plugin_caption_caption'); 61 $this->Lexer->addPattern('<caption>(?=.*</caption>)','plugin_caption_caption'); 62 $this->Lexer->addPattern('</caption>','plugin_caption_caption'); 63 } 64 65 public function postConnect() { 66 $this->Lexer->addExitPattern('</figure>','plugin_caption_caption'); 67 $this->Lexer->addExitPattern('</table>','plugin_caption_caption'); 68 $this->Lexer->addExitPattern('</codeblock>','plugin_caption_caption'); 69 $this->Lexer->addExitPattern('</fileblock>','plugin_caption_caption'); 70 } 71 72 public function handle($match, $state, $pos, Doku_Handler $handler){ 73 switch ($state) { 74 case DOKU_LEXER_ENTER : 75 $match = substr($match,1,-1); 76 return array($state, $match); 77 case DOKU_LEXER_MATCHED : 78 return array($state, $match); 79 case DOKU_LEXER_UNMATCHED : 80 return array($state, $match); 81 case DOKU_LEXER_EXIT : 82 $match = substr($match,1,-1); 83 return array($state, $match); 84 case DOKU_LEXER_SPECIAL : 85 if (!(strpos($match,'{{setcounter')===false)) { 86 return array($state, substr($match,13,-2)); 87 } 88 } 89 return array(); 90 } 91 92 public function render($mode, Doku_Renderer $renderer, $data) { 93 if ($mode == 'xhtml') { 94 95 list($state,$match) = $data; 96 97 switch ($state) { 98 case DOKU_LEXER_ENTER : 99 // Handle case that there is a label in the opening tag 100 // Fix warnings in PHP >=8.1, not relying on "sexplode" in DW Jack Jackrum 101 $label = count(explode(' ',$match)) > 1 ? explode(' ',$match)[1] : null; 102 if (in_array(explode(' ',$match)[0],$this->_types)) { 103 $this->_type = explode(' ',$match)[0]; 104 switch ($this->_type) { 105 case "figure" : 106 $renderer->doc .= '<figure class="plugin_caption_figure"'; 107 // If we have a label, assign it to the global label array 108 if ($label) { 109 global $caption_labels; 110 $caption_labels[$label] = $this->_fignum; 111 $this->_figlabels[$this->_fignum] = $label; 112 $renderer->doc .= ' id="'.$renderer->_xmlEntities($label).'"'; 113 // WARNING: Potential harmful way of handling references 114 // that have already been printed 115 $pattern = '##REF:'.$this->_figlabels[$this->_fignum].'##'; 116 if (strpos($renderer->doc, $pattern) !== FALSE) { 117 $renderer->doc = str_replace($pattern, $this->_fignum, $renderer->doc); 118 } 119 } 120 $renderer->doc .= '>'; 121 break; 122 case "table" : 123 $renderer->doc .= '<div class="plugin_caption_table"'; 124 // If we have a label, assign it to the global label array 125 if ($label) { 126 global $caption_labels; 127 $caption_labels[$label] = $this->_tabnum; 128 $this->_tablabels[$this->_tabnum] = $label; 129 $renderer->doc .= ' id="'.$renderer->_xmlEntities($label).'"'; 130 // WARNING: Potential harmful way of handling references 131 // that have already been printed 132 $pattern = '##REF:'.$this->_tablabels[$this->_tabnum].'##'; 133 if (strpos($renderer->doc, $pattern) !== FALSE) { 134 $renderer->doc = str_replace($pattern, $this->_tabnum, $renderer->doc); 135 } 136 } 137 $renderer->doc .= '>'; 138 break; 139 case "codeblock" : 140 $renderer->doc .= '<div class="plugin_caption_codeblock"'; 141 // If we have a label, assign it to the global label array 142 if ($label) { 143 global $caption_labels; 144 $caption_labels[$label] = $this->_tabnum; 145 $this->_codelabels[$this->_codenum] = $label; 146 $renderer->doc .= ' id="'.$renderer->_xmlEntities($label).'"'; 147 // WARNING: Potential harmful way of handling references 148 // that have already been printed 149 if(isset($this->_codelabels[$this->_codenum])) { 150 $pattern = '##REF:'.$this->_codelabels[$this->_codenum].'##'; 151 if (strpos($renderer->doc, $pattern) !== FALSE) { 152 $renderer->doc = str_replace($pattern, $this->_codenum, $renderer->doc); 153 } 154 } 155 } 156 $renderer->doc .= '>'; 157 break; 158 case "fileblock" : 159 $renderer->doc .= '<div class="plugin_caption_fileblock"'; 160 // If we have a label, assign it to the global label array 161 if ($label) { 162 global $caption_labels; 163 $caption_labels[$label] = $this->_filenum; 164 $this->_tablabels[$this->_filenum] = $label; 165 $renderer->doc .= ' id="'.$renderer->_xmlEntities($label).'"'; 166 // WARNING: Potential harmful way of handling references 167 // that have already been printed 168 $pattern = '##REF:'.$this->_filelabels[$this->_filenum].'##'; 169 if (strpos($renderer->doc, $pattern) !== FALSE) { 170 $renderer->doc = str_replace($pattern, $this->_filenum, $renderer->doc); 171 } 172 } 173 $renderer->doc .= '>'; 174 break; 175 } 176 } 177 break; 178 179 case DOKU_LEXER_MATCHED : 180 // return the dokuwiki markup within the caption tags 181 if (!$this->_incaption) { 182 $this->_incaption = true; 183 switch ($this->_type) { 184 case "figure" : 185 $renderer->doc .= '<figcaption class="plugin_caption_caption"><span class="plugin_caption_caption_number"'; 186 if(array_key_exists($this->_fignum,$this->_figlabels)) { 187 $renderer->doc .= ' title="' 188 .$this->_figlabels[$this->_fignum].'"'; 189 } 190 $renderer->doc .= '>'; 191 if ($this->getConf('abbrev')) { 192 $renderer->doc .= $this->getLang('figureabbrev'); 193 } else { 194 $renderer->doc .= $this->getLang('figurelong'); 195 } 196 $renderer->doc .= ' ' . $this->_fignum . ':</span>'; 197 $renderer->doc .= ' <span class="plugin_caption_caption_text">'; 198 break; 199 case "table" : 200 $renderer->doc .= '<div class="plugin_caption_caption"><span class="plugin_caption_caption_number"'; 201 if(array_key_exists($this->_tabnum,$this->_tablabels)) { 202 $renderer->doc .= ' title="' 203 .$this->_tablabels[$this->_tabnum].'"'; 204 } 205 $renderer->doc .= '>'; 206 if ($this->getConf('abbrev')) { 207 $renderer->doc .= $this->getLang('tableabbrev'); 208 } else { 209 $renderer->doc .= $this->getLang('tablelong'); 210 } 211 $renderer->doc .= ' ' . $this->_tabnum . ':</span>'; 212 $renderer->doc .= ' <span class="captiontext">'; 213 break; 214 case "codeblock" : 215 $renderer->doc .= '<div class="plugin_caption_caption"><span class="plugin_caption_caption_number"'; 216 if(array_key_exists($this->_codenum,$this->_codelabels)) { 217 $renderer->doc .= ' title="' 218 .$this->_codelabels[$this->_codenum].'"'; 219 } 220 $renderer->doc .= '>'; 221 if ($this->getConf('abbrev')) { 222 $renderer->doc .= $this->getLang('codeabbrev'); 223 } else { 224 $renderer->doc .= $this->getLang('codelong'); 225 } 226 $renderer->doc .= ' ' . $this->_codenum . ':</span>'; 227 $renderer->doc .= ' <span class="captiontext">'; 228 break; 229 case "fileblock" : 230 $renderer->doc .= '<div class="plugin_caption_caption"><span class="plugin_caption_caption_number"'; 231 if(array_key_exists($this->_filenum,$this->_filelabels)) { 232 $renderer->doc .= ' title="' 233 .$this->_tablabels[$this->_filenum].'"'; 234 } 235 $renderer->doc .= '>'; 236 if ($this->getConf('abbrev')) { 237 $renderer->doc .= $this->getLang('fileabbrev'); 238 } else { 239 $renderer->doc .= $this->getLang('filelong'); 240 } 241 $renderer->doc .= ' ' . $this->_filenum . ':</span>'; 242 $renderer->doc .= ' <span class="captiontext">'; 243 break; 244 } 245 } else { 246 $this->_incaption = false; 247 switch ($this->_type) { 248 case "figure" : 249 $renderer->doc .= '</span></figcaption>'; 250 break; 251 case "table" : 252 $renderer->doc .= '</span></div>'; 253 break; 254 case "codeblock" : 255 $renderer->doc .= '</span></div>'; 256 break; 257 case "fileblock" : 258 $renderer->doc .= '</span></div>'; 259 break; 260 } 261 } 262 break; 263 264 case DOKU_LEXER_UNMATCHED : 265 // return the dokuwiki markup within the figure tags 266 $renderer->doc .= $renderer->_xmlEntities($match); 267 break; 268 269 case DOKU_LEXER_EXIT : 270 // increment figure/table number 271 switch ($this->_type) { 272 case "figure" : 273 $this->_fignum++; 274 $renderer->doc .= '</figure>'; 275 break; 276 case "table" : 277 $this->_tabnum++; 278 $renderer->doc .= '</div>'; 279 break; 280 case "codeblock" : 281 $this->_codenum++; 282 $renderer->doc .= '</div>'; 283 break; 284 case "fileblock" : 285 $this->_filenum++; 286 $renderer->doc .= '</div>'; 287 break; 288 } 289 $this->_type = ''; 290 break; 291 292 case DOKU_LEXER_SPECIAL : 293 list($_type,$_num) = explode('=',trim($match)); 294 $_type = trim($_type); 295 $_num = (int) trim($_num); 296 if (in_array($_type,$this->_types)) { 297 switch ($_type) { 298 case "figure" : 299 $this->_fignum = $_num; 300 break; 301 case "table" : 302 $this->_tabnum = $_num; 303 break; 304 case "codeblock" : 305 $this->_codenum = $_num; 306 break; 307 case "fileblock" : 308 $this->_filenum = $_num; 309 break; 310 } 311 } 312 break; 313 } 314 return true; 315 } 316 317 if ($mode == 'latex') { 318 319 list($state,$match) = $data; 320 321 switch ($state) { 322 case DOKU_LEXER_ENTER : 323 // Handle case that there is a label in the opening tag 324 list($match,$label) = explode(' ',$match); 325 if (in_array($match,$this->_types)) { 326 $this->_type = $match; 327 switch ($this->_type) { 328 case "figure" : 329 $renderer->doc .= '\begin{figure}'; 330 // If we have a label, assign it to the global label array 331 if ($label) { 332 $this->_label = $label; 333 } 334 break; 335 case "table" : 336 $renderer->doc .= '\begin{table}'; 337 if ($label) { 338 $this->_label = $label; 339 } 340 break; 341 } 342 } 343 break; 344 345 case DOKU_LEXER_MATCHED : 346 // return the dokuwiki markup within the caption tags 347 if (!$this->_incaption) { 348 $this->_incaption = true; 349 $renderer->doc .= '\caption{'; 350 } else { 351 $renderer->doc .= '}'; 352 $this->_incaption = false; 353 if ($this->_label) { 354 $renderer->doc .= "\n" . '\label{'.$this->_label.'}'; 355 $this->_label = ''; 356 } 357 } 358 break; 359 360 case DOKU_LEXER_UNMATCHED : 361 // return the dokuwiki markup within the figure tags 362 $renderer->doc .= $match; //$renderer->_xmlEntities($match); 363 break; 364 365 case DOKU_LEXER_EXIT : 366 switch ($this->_type) { 367 case "figure" : 368 $renderer->doc .= '\end{figure}' . "\n\n"; 369 break; 370 case "table" : 371 $renderer->doc .= '\end{table}' . "\n\n"; 372 break; 373 } 374 $this->_type = ''; 375 break; 376 } 377 return true; 378 } 379 380 /** 381 * WARNING: The odt mode seems to work in general, but strange things happen 382 * with the tables - therefore, within the table tags only a table 383 * is allowed, without any additional markup. 384 */ 385 if ($mode == 'odt') { 386 387 list($state,$match) = $data; 388 389 switch ($state) { 390 case DOKU_LEXER_ENTER : 391 // Handle case that there is a label in the opening tag 392 list($match,$label) = explode(' ',$match); 393 if (in_array($match,$this->_types)) { 394 $this->_type = $match; 395 switch ($this->_type) { 396 case "figure" : 397 // If we have a label, assign it to the global label array 398 if ($label) { 399 global $caption_labels; 400 $caption_labels[$label] = $this->_fignum; 401 $this->_label = $label; 402 } 403 break; 404 case "table" : 405 // If we have a label, assign it to the global label array 406 if ($label) { 407 global $caption_labels; 408 $caption_labels[$label] = $this->_tabnum; 409 $this->_label = $label; 410 } 411 break; 412 } 413 $renderer->p_open(); 414 } 415 break; 416 417 case DOKU_LEXER_MATCHED : 418 // return the dokuwiki markup within the caption tags 419 if (!$this->_incaption) { 420 $this->_incaption = true; 421 $renderer->p_close(); 422 switch ($this->_type) { 423 case "figure" : 424 if ($this->getConf('abbrev')) { 425 $renderer->cdata($this->getLang('figureabbrev')); 426 } else { 427 $renderer->cdata($this->getLang('figurelong')); 428 } 429 $renderer->cdata(" " . $this->_fignum . ": "); 430 break; 431 case "table" : 432 if ($this->getConf('abbrev')) { 433 $renderer->cdata($this->getLang('tableabbrev')); 434 } else { 435 $renderer->cdata($this->getLang('tablelong')); 436 } 437 $renderer->cdata(" " . $this->_tabnum . ": "); 438 break; 439 } 440 } else { 441 $this->_incaption = false; 442 switch ($this->_type) { 443 case "figure" : 444 $renderer->p_open(); 445 break; 446 case "table" : 447// $renderer->p_open(); 448 break; 449 } 450 } 451 break; 452 453 case DOKU_LEXER_UNMATCHED : 454 // return the dokuwiki markup within the figure tags 455 $renderer->cdata($match); 456 break; 457 458 case DOKU_LEXER_EXIT : 459 // increment figure/table number 460 switch ($this->_type) { 461 case "figure" : 462 $this->_fignum++; 463 $renderer->p_close(); 464 break; 465 case "table" : 466 $this->_tabnum++; 467 break; 468 } 469 $this->_type = ''; 470 break; 471 } 472 return true; 473 } 474 475 // unsupported $mode 476 return false; 477 } 478} 479 480// vim:ts=4:sw=4:et: 481