1<?php 2/** 3 * DokuWiki Plugin dw2markdown (Renderer Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author i-net software <tools@inetsoftware.de> 7 */ 8 9// must be run within Dokuwiki 10if (!defined('DOKU_INC')) die(); 11 12require_once DOKU_INC.'inc/parser/renderer.php'; 13 14 15class Renderer_Plugin_dw2markdown extends Doku_Renderer_xhtml { 16 17 function document_start() { 18 global $ID; 19 20 $this->doc = ''; 21 $toc = array(); 22 $footnotes = array(); 23 $store = ''; 24 $nSpan = 0; 25 $separator = ''; 26 27 $metaheader = array(); 28 $metaheader['Content-Type'] = 'plain/text; charset=iso-8859-1'; 29 $metaheader['Content-Disposition'] = 'attachment; filename="' . noNS($ID) . '.md"'; 30 $meta = array(); 31 $meta['format']['dw2markdown'] = $metaheader; 32 p_set_metadata($ID,$meta); 33 } 34 35 // FIXME implement all methods of Doku_Renderer here 36 public function document_end(){ 37 //$converter = new DokuWikiToMarkdown(); 38 //$this->doc = $converter->convert( $this->doc ); 39 40 $this->doc = preg_replace("/(\r?\n){3,}/", "\n\n", $this->doc); 41 $this->doc = preg_replace("/^\s+/", "", $this->doc); // remove leading space and empty lines 42 } 43 44 /** 45 * Render a heading 46 * 47 * @param string $text the text to display 48 * @param int $level header level 49 * @param int $pos byte position in the original source 50 */ 51 function header($text, $level, $pos, $returnonly = false) { 52 $this->doc .= str_repeat("#", $level) . ' ' . $text . DOKU_LF; 53 } 54 55 /** 56 * Open a new section 57 * 58 * @param int $level section level (as determined by the previous header) 59 */ 60 function section_open($level) { 61 $this->doc .= DOKU_LF; 62 } 63 64 /** 65 * Close the current section 66 */ 67 function section_close() { 68 $this->doc .= DOKU_LF; 69 } 70 71 /** 72 * Render plain text data 73 * 74 * @param string $text 75 */ 76 function cdata($text) { 77 $this->doc .= $text; 78 } 79 80 /** 81 * Open a paragraph 82 */ 83 function p_open() { 84 $this->doc .= DOKU_LF; 85 } 86 87 /** 88 * Close a paragraph 89 */ 90 function p_close() { 91 $this->doc .= DOKU_LF; 92 } 93 94 /** 95 * Create a line break 96 */ 97 function linebreak() { 98 $this->doc .= DOKU_LF . DOKU_LF; 99 } 100 101 /** 102 * Create a horizontal line 103 */ 104 function hr() { 105 $this->doc .= '----'; 106 } 107 108 /** 109 * Start strong (bold) formatting 110 */ 111 function strong_open() { 112 $this->doc .= '**'; 113 } 114 115 /** 116 * Stop strong (bold) formatting 117 */ 118 function strong_close() { 119 $this->doc .= '**'; 120 } 121 122 /** 123 * Start emphasis (italics) formatting 124 */ 125 function emphasis_open() { 126 $this->doc .= '*'; 127 } 128 129 /** 130 * Stop emphasis (italics) formatting 131 */ 132 function emphasis_close() { 133 $this->doc .= '*'; 134 } 135 136 /** 137 * Start underline formatting 138 */ 139 function underline_open() { 140 $this->doc .= '__'; 141 } 142 143 /** 144 * Stop underline formatting 145 */ 146 function underline_close() { 147 $this->doc .= '__'; 148 } 149 150 /** 151 * Start monospace formatting 152 */ 153 function monospace_open() { 154 $this->doc .= "`"; 155 } 156 157 /** 158 * Stop monospace formatting 159 */ 160 function monospace_close() { 161 $this->doc .= "`"; 162 } 163 164 /** 165 * Start a subscript 166 */ 167 function subscript_open() { 168 $this->doc .= '<sub>'; 169 } 170 171 /** 172 * Stop a subscript 173 */ 174 function subscript_close() { 175 $this->doc .= '</sub>'; 176 } 177 178 /** 179 * Start a superscript 180 */ 181 function superscript_open() { 182 $this->doc .= '<sup>'; 183 } 184 185 /** 186 * Stop a superscript 187 */ 188 function superscript_close() { 189 $this->doc .= '</sup>'; 190 } 191 192 /** 193 * Start deleted (strike-through) formatting 194 */ 195 function deleted_open() { 196 $this->doc .= '~~'; 197 } 198 199 /** 200 * Stop deleted (strike-through) formatting 201 */ 202 function deleted_close() { 203 $this->doc .= '~~'; 204 } 205 206 /** 207 * Start a footnote 208 */ 209 function footnote_open() { 210 $this->doc .= '(('; 211 } 212 213 /** 214 * Stop a footnote 215 */ 216 function footnote_close() { 217 $this->doc .= '))'; 218 } 219 220 private $listMode = []; 221 222 /** 223 * Open an unordered list 224 */ 225 function listu_open($classes = null) { 226 array_push( $this->listMode, '*' ); 227 } 228 229 /** 230 * Close an unordered list 231 */ 232 function listu_close() { 233 array_pop( $this->listMode ); 234 if ( empty($this->listMode) ) { 235 $this->doc .= DOKU_LF; 236 } 237 } 238 239 /** 240 * Open an ordered list 241 */ 242 function listo_open($classes = null) { 243 array_push( $this->listMode, '1.' ); 244 } 245 246 /** 247 * Close an ordered list 248 */ 249 function listo_close() { 250 array_pop( $this->listMode ); 251 if ( empty($this->listMode) ) { 252 $this->doc .= DOKU_LF; 253 } 254 } 255 256 /** 257 * Open a list item 258 * 259 * @param int $level the nesting level 260 * @param bool $node true when a node; false when a leaf 261 */ 262 function listitem_open($level,$node=false) { 263 $this->doc .= DOKU_LF; 264 $this->doc .= str_repeat(' ', $level*2) . $this->listMode[count($this->listMode)-1]; 265 } 266 267 /** 268 * Close a list item 269 */ 270 function listitem_close() { 271// $this->doc .= DOKU_LF; 272 } 273 274 /** 275 * Start the content of a list item 276 */ 277 function listcontent_open() { 278 } 279 280 /** 281 * Stop the content of a list item 282 */ 283 function listcontent_close() { 284// $this->doc .= DOKU_LF; 285 } 286 287 /** 288 * Output unformatted $text 289 * 290 * Defaults to $this->cdata() 291 * 292 * @param string $text 293 */ 294 function unformatted($text) { 295 $this->cdata($text); 296 } 297 298 /** 299 * Output inline PHP code 300 * 301 * If $conf['phpok'] is true this should evaluate the given code and append the result 302 * to $doc 303 * 304 * @param string $text The PHP code 305 */ 306 function php($text, $wrapper = 'code') { 307 $this->code($text, 'php'); 308 } 309 310 /** 311 * Output block level PHP code 312 * 313 * If $conf['phpok'] is true this should evaluate the given code and append the result 314 * to $doc 315 * 316 * @param string $text The PHP code 317 */ 318 function phpblock($text) { 319 $this->php($text); 320 } 321 322 /** 323 * Output raw inline HTML 324 * 325 * If $conf['htmlok'] is true this should add the code as is to $doc 326 * 327 * @param string $text The HTML 328 */ 329 function html($text, $wrapper = 'code') { 330 $this->code($text, 'html'); 331 } 332 333 /** 334 * Output raw block-level HTML 335 * 336 * If $conf['htmlok'] is true this should add the code as is to $doc 337 * 338 * @param string $text The HTML 339 */ 340 function htmlblock($text) { 341 $this->html($text); 342 } 343 344 /** 345 * Output preformatted text 346 * 347 * @param string $text 348 */ 349 function preformatted($text) { 350 $this->doc .= DOKU_LF . "\t" . implode( "\n\t", explode("\n", $text) ); 351 } 352 353 /** 354 * Start a block quote 355 */ 356 function quote_open() { 357 } 358 359 /** 360 * Stop a block quote 361 */ 362 function quote_close() { 363 } 364 365 /** 366 * Display text as file content, optionally syntax highlighted 367 * 368 * @param string $text text to show 369 * @param string $lang programming language to use for syntax highlighting 370 * @param string $file file path label 371 */ 372 function file($text, $language = NULL, $filename = NULL, $options = NULL) { 373 } 374 375 /** 376 * Display text as code content, optionally syntax highlighted 377 * 378 * @param string $text text to show 379 * @param string $lang programming language to use for syntax highlighting 380 * @param string $file file path label 381 */ 382 function code($text, $language = NULL, $filename = NULL, $options = NULL) { 383 $this->doc .= DOKU_LF . '```' . $language . DOKU_LF . trim($text) . DOKU_LF . '```' . DOKU_LF; 384 } 385 386 /** 387 * Format an acronym 388 * 389 * Uses $this->acronyms 390 * 391 * @param string $acronym 392 */ 393 function acronym($acronym) { 394 $this->doc .= $acronym; 395 } 396 397 /** 398 * Format a smiley 399 * 400 * Uses $this->smiley 401 * 402 * @param string $smiley 403 */ 404 function smiley($smiley) { 405 $this->doc .= $smiley; 406 } 407 408 /** 409 * Format an entity 410 * 411 * Entities are basically small text replacements 412 * 413 * Uses $this->entities 414 * 415 * @param string $entity 416 */ 417 /*function entity($entity) { 418 $this->doc .= $entity; 419 }*/ 420 421 /** 422 * Typographically format a multiply sign 423 * 424 * Example: ($x=640, $y=480) should result in "640×480" 425 * 426 * @param string|int $x first value 427 * @param string|int $y second value 428 */ 429 /*function multiplyentity($x, $y) { 430 $this->doc .= "$x×$y"; 431 }*/ 432 433 /** 434 * Render an opening single quote char (language specific) 435 */ 436 function singlequoteopening() { 437 $this->doc .= "'"; 438 } 439 440 /** 441 * Render a closing single quote char (language specific) 442 */ 443 function singlequoteclosing() { 444 $this->doc .= "'"; 445 } 446 447 /** 448 * Render an apostrophe char (language specific) 449 */ 450 function apostrophe() { 451 } 452 453 /** 454 * Render an opening double quote char (language specific) 455 */ 456 function doublequoteopening() { 457 $this->doc .= '"'; 458 } 459 460 /** 461 * Render an closinging double quote char (language specific) 462 */ 463 function doublequoteclosing() { 464 $this->doc .= '"'; 465 } 466 467 /** 468 * Render the output of an RSS feed 469 * 470 * @param string $url URL of the feed 471 * @param array $params Finetuning of the output 472 */ 473 function rss($url, $params) { 474 $this->externallink( $url ); 475 } 476 /** 477 * Start a table 478 * 479 * @param int $maxcols maximum number of columns 480 * @param int $numrows NOT IMPLEMENTED 481 * @param int $pos byte position in the original source 482 */ 483 function table_open($maxcols = null, $numrows = null, $pos = null, $classes = null) { 484 } 485 486 /** 487 * Close a table 488 * 489 * @param int $pos byte position in the original source 490 */ 491 function table_close($pos = null) { 492 $this->doc .= DOKU_LF; 493 } 494 495 private $tableColumns = 0; 496 497 /** 498 * Open a table header 499 */ 500 function tablethead_open() { 501 $this->tableColumns = 0; 502 $this->doc .= DOKU_LF; // . '|'; 503 } 504 505 /** 506 * Close a table header 507 */ 508 function tablethead_close() { 509 $this->doc .= '|' . str_repeat('---|', $this->tableColumns) . DOKU_LF; 510 } 511 512 /** 513 * Open a table body 514 */ 515 function tabletbody_open() { 516 } 517 518 /** 519 * Close a table body 520 */ 521 function tabletbody_close() { 522 } 523 524 /** 525 * Open a table row 526 */ 527 function tablerow_open($classes = null) { 528 } 529 530 /** 531 * Close a table row 532 */ 533 function tablerow_close() { 534 $this->doc .= '|' . DOKU_LF; 535 } 536 537 /** 538 * Open a table header cell 539 * 540 * @param int $colspan 541 * @param string $align left|center|right 542 * @param int $rowspan 543 */ 544 function tableheader_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) { 545 $this->doc .= str_repeat( '|', $colspan ); 546 $this->tableColumns += $colspan; 547 } 548 549 /** 550 * Close a table header cell 551 */ 552 function tableheader_close() { 553 } 554 555 /** 556 * Open a table cell 557 * 558 * @param int $colspan 559 * @param string $align left|center|right 560 * @param int $rowspan 561 */ 562 function tablecell_open($colspan = 1, $align = null, $rowspan = 1, $classes = null) { 563 $this->doc .= str_repeat( '|', $colspan ); 564 } 565 566 /** 567 * Close a table cell 568 */ 569 function tablecell_close() { 570 } 571 572 function getFormat() { 573 return 'markdown'; 574 } 575 576 /** 577 * Render a page local link 578 * 579 * @param string $hash hash link identifier 580 * @param string $name name for the link 581 * @param bool $returnonly whether to return html or write to doc attribute 582 * @return void|string writes to doc attribute or returns html depends on $returnonly 583 */ 584 public function locallink($hash, $name = null, $returnonly = false) { 585 global $ID; 586 $name = $this->_getLinkTitle($name, $hash, $isImage); 587 $hash = $this->_headerToLink($hash); 588 589 $doc = '['.$name.'](#'.$hash.')'; 590 591 if($returnonly) { 592 return $doc; 593 } else { 594 $this->doc .= $doc; 595 } 596 } 597 598 #endregion 599 /** 600 * Build a link 601 * 602 * Assembles all parts defined in $link returns HTML for the link 603 * 604 * @param array $link attributes of a link 605 * @return string 606 * 607 * @author Andreas Gohr <andi@splitbrain.org> 608 */ 609 public function _formatLink($link) { 610 //make sure the url is XHTML compliant (skip mailto) 611 if(substr($link['url'], 0, 7) != 'mailto:') { 612 $link['url'] = str_replace('&', '&', $link['url']); 613 $link['url'] = str_replace('&amp;', '&', $link['url']); 614 } 615 //remove double encodings in titles 616 $link['title'] = str_replace('&amp;', '&', $link['title']); 617 618 // be sure there are no bad chars in url or title 619 // (we can't do this for name because it can contain an img tag) 620 $link['url'] = strtr($link['url'], array('>' => '%3E', '<' => '%3C', '"' => '%22')); 621 $link['title'] = strtr($link['title'], array('>' => '>', '<' => '<', '"' => '"')); 622 623 $res = $link['pre'] . '[' . $link['name'] . '](' . $link['url'] . ')' . $link['suf']; 624 return $res; 625 } 626} 627