1<?php 2/** 3 * Renderer output base class 4 * 5 * @author Harry Fuecks <hfuecks@gmail.com> 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8if(!defined('DOKU_INC')) die('meh.'); 9 10/** 11 * An empty renderer, produces no output 12 * 13 * Inherits from DokuWiki_Plugin for giving additional functions to render plugins 14 * 15 * The renderer transforms the syntax instructions created by the parser and handler into the 16 * desired output format. For each instruction a corresponding method defined in this class will 17 * be called. That method needs to produce the desired output for the instruction and add it to the 18 * $doc field. When all instructions are processed, the $doc field contents will be cached by 19 * DokuWiki and sent to the user. 20 */ 21class Doku_Renderer extends DokuWiki_Plugin { 22 /** @var array Settings, control the behavior of the renderer */ 23 public $info = array( 24 'cache' => true, // may the rendered result cached? 25 'toc' => true, // render the TOC? 26 ); 27 28 /** @var array contains the smiley configuration, set in p_render() */ 29 public $smileys = array(); 30 /** @var array contains the entity configuration, set in p_render() */ 31 public $entities = array(); 32 /** @var array contains the acronym configuration, set in p_render() */ 33 public $acronyms = array(); 34 /** @var array contains the interwiki configuration, set in p_render() */ 35 public $interwiki = array(); 36 37 /** 38 * @var string the rendered document, this will be cached after the renderer ran through 39 */ 40 public $doc = ''; 41 42 /** 43 * clean out any per-use values 44 * 45 * This is called before each use of the renderer object and should be used to 46 * completely reset the state of the renderer to be reused for a new document 47 */ 48 function reset() { 49 } 50 51 /** 52 * Allow the plugin to prevent DokuWiki from reusing an instance 53 * 54 * Since most renderer plugins fail to implement Doku_Renderer::reset() we default 55 * to reinstantiating the renderer here 56 * 57 * @return bool false if the plugin has to be instantiated 58 */ 59 function isSingleton() { 60 return false; 61 } 62 63 /** 64 * Returns the format produced by this renderer. 65 * 66 * Has to be overidden by sub classes 67 * 68 * @return string 69 */ 70 function getFormat() { 71 trigger_error('getFormat() not implemented in '.get_class($this), E_USER_WARNING); 72 return ''; 73 } 74 75 /** 76 * Disable caching of this renderer's output 77 */ 78 function nocache() { 79 $this->info['cache'] = false; 80 } 81 82 /** 83 * Disable TOC generation for this renderer's output 84 * 85 * This might not be used for certain sub renderer 86 */ 87 function notoc() { 88 $this->info['toc'] = false; 89 } 90 91 /** 92 * Handle plugin rendering 93 * 94 * Most likely this needs NOT to be overwritten by sub classes 95 * 96 * @param string $name Plugin name 97 * @param mixed $data custom data set by handler 98 * @param string $state matched state if any 99 * @param string $match raw matched syntax 100 */ 101 function plugin($name, $data, $state = '', $match = '') { 102 /** @var DokuWiki_Syntax_Plugin $plugin */ 103 $plugin = plugin_load('syntax', $name); 104 if($plugin != null) { 105 $plugin->render($this->getFormat(), $this, $data); 106 } 107 } 108 109 /** 110 * handle nested render instructions 111 * this method (and nest_close method) should not be overloaded in actual renderer output classes 112 * 113 * @param array $instructions 114 */ 115 function nest($instructions) { 116 foreach($instructions as $instruction) { 117 // execute the callback against ourself 118 if(method_exists($this, $instruction[0])) { 119 call_user_func_array(array($this, $instruction[0]), $instruction[1] ? $instruction[1] : array()); 120 } 121 } 122 } 123 124 /** 125 * dummy closing instruction issued by Doku_Handler_Nest 126 * 127 * normally the syntax mode should override this instruction when instantiating Doku_Handler_Nest - 128 * however plugins will not be able to - as their instructions require data. 129 */ 130 function nest_close() { 131 } 132 133 #region Syntax modes - sub classes will need to implement them to fill $doc 134 135 /** 136 * Initialize the document 137 */ 138 function document_start() { 139 } 140 141 /** 142 * Finalize the document 143 */ 144 function document_end() { 145 } 146 147 /** 148 * Render the Table of Contents 149 * 150 * @return string 151 */ 152 function render_TOC() { 153 return ''; 154 } 155 156 /** 157 * Add an item to the TOC 158 * 159 * @param string $id the hash link 160 * @param string $text the text to display 161 * @param int $level the nesting level 162 */ 163 function toc_additem($id, $text, $level) { 164 } 165 166 /** 167 * Render a heading 168 * 169 * @param string $text the text to display 170 * @param int $level header level 171 * @param int $pos byte position in the original source 172 */ 173 function header($text, $level, $pos) { 174 } 175 176 /** 177 * Open a new section 178 * 179 * @param int $level section level (as determined by the previous header) 180 */ 181 function section_open($level) { 182 } 183 184 /** 185 * Close the current section 186 */ 187 function section_close() { 188 } 189 190 /** 191 * Render plain text data 192 * 193 * @param string $text 194 */ 195 function cdata($text) { 196 } 197 198 /** 199 * Open a paragraph 200 */ 201 function p_open() { 202 } 203 204 /** 205 * Close a paragraph 206 */ 207 function p_close() { 208 } 209 210 /** 211 * Create a line break 212 */ 213 function linebreak() { 214 } 215 216 /** 217 * Create a horizontal line 218 */ 219 function hr() { 220 } 221 222 /** 223 * Start strong (bold) formatting 224 */ 225 function strong_open() { 226 } 227 228 /** 229 * Stop strong (bold) formatting 230 */ 231 function strong_close() { 232 } 233 234 /** 235 * Start emphasis (italics) formatting 236 */ 237 function emphasis_open() { 238 } 239 240 /** 241 * Stop emphasis (italics) formatting 242 */ 243 function emphasis_close() { 244 } 245 246 /** 247 * Start underline formatting 248 */ 249 function underline_open() { 250 } 251 252 /** 253 * Stop underline formatting 254 */ 255 function underline_close() { 256 } 257 258 /** 259 * Start monospace formatting 260 */ 261 function monospace_open() { 262 } 263 264 /** 265 * Stop monospace formatting 266 */ 267 function monospace_close() { 268 } 269 270 /** 271 * Start a subscript 272 */ 273 function subscript_open() { 274 } 275 276 /** 277 * Stop a subscript 278 */ 279 function subscript_close() { 280 } 281 282 /** 283 * Start a superscript 284 */ 285 function superscript_open() { 286 } 287 288 /** 289 * Stop a superscript 290 */ 291 function superscript_close() { 292 } 293 294 /** 295 * Start deleted (strike-through) formatting 296 */ 297 function deleted_open() { 298 } 299 300 /** 301 * Stop deleted (strike-through) formatting 302 */ 303 function deleted_close() { 304 } 305 306 /** 307 * Start a footnote 308 */ 309 function footnote_open() { 310 } 311 312 /** 313 * Stop a footnote 314 */ 315 function footnote_close() { 316 } 317 318 /** 319 * Open an unordered list 320 */ 321 function listu_open() { 322 } 323 324 /** 325 * Close an unordered list 326 */ 327 function listu_close() { 328 } 329 330 /** 331 * Open an ordered list 332 */ 333 function listo_open() { 334 } 335 336 /** 337 * Close an ordered list 338 */ 339 function listo_close() { 340 } 341 342 /** 343 * Open a list item 344 * 345 * @param int $level the nesting level 346 * @param bool $node true when a node; false when a leaf 347 */ 348 function listitem_open($level,$node=false) { 349 } 350 351 /** 352 * Close a list item 353 */ 354 function listitem_close() { 355 } 356 357 /** 358 * Start the content of a list item 359 */ 360 function listcontent_open() { 361 } 362 363 /** 364 * Stop the content of a list item 365 */ 366 function listcontent_close() { 367 } 368 369 /** 370 * Output unformatted $text 371 * 372 * Defaults to $this->cdata() 373 * 374 * @param string $text 375 */ 376 function unformatted($text) { 377 $this->cdata($text); 378 } 379 380 /** 381 * Output inline PHP code 382 * 383 * If $conf['phpok'] is true this should evaluate the given code and append the result 384 * to $doc 385 * 386 * @param string $text The PHP code 387 */ 388 function php($text) { 389 } 390 391 /** 392 * Output block level PHP code 393 * 394 * If $conf['phpok'] is true this should evaluate the given code and append the result 395 * to $doc 396 * 397 * @param string $text The PHP code 398 */ 399 function phpblock($text) { 400 } 401 402 /** 403 * Output raw inline HTML 404 * 405 * If $conf['htmlok'] is true this should add the code as is to $doc 406 * 407 * @param string $text The HTML 408 */ 409 function html($text) { 410 } 411 412 /** 413 * Output raw block-level HTML 414 * 415 * If $conf['htmlok'] is true this should add the code as is to $doc 416 * 417 * @param string $text The HTML 418 */ 419 function htmlblock($text) { 420 } 421 422 /** 423 * Output preformatted text 424 * 425 * @param string $text 426 */ 427 function preformatted($text) { 428 } 429 430 /** 431 * Start a block quote 432 */ 433 function quote_open() { 434 } 435 436 /** 437 * Stop a block quote 438 */ 439 function quote_close() { 440 } 441 442 /** 443 * Display text as file content, optionally syntax highlighted 444 * 445 * @param string $text text to show 446 * @param string $lang programming language to use for syntax highlighting 447 * @param string $file file path label 448 */ 449 function file($text, $lang = null, $file = null) { 450 } 451 452 /** 453 * Display text as code content, optionally syntax highlighted 454 * 455 * @param string $text text to show 456 * @param string $lang programming language to use for syntax highlighting 457 * @param string $file file path label 458 */ 459 function code($text, $lang = null, $file = null) { 460 } 461 462 /** 463 * Format an acronym 464 * 465 * Uses $this->acronyms 466 * 467 * @param string $acronym 468 */ 469 function acronym($acronym) { 470 } 471 472 /** 473 * Format a smiley 474 * 475 * Uses $this->smiley 476 * 477 * @param string $smiley 478 */ 479 function smiley($smiley) { 480 } 481 482 /** 483 * Format an entity 484 * 485 * Entities are basically small text replacements 486 * 487 * Uses $this->entities 488 * 489 * @param string $entity 490 */ 491 function entity($entity) { 492 } 493 494 /** 495 * Typographically format a multiply sign 496 * 497 * Example: ($x=640, $y=480) should result in "640×480" 498 * 499 * @param string|int $x first value 500 * @param string|int $y second value 501 */ 502 function multiplyentity($x, $y) { 503 } 504 505 /** 506 * Render an opening single quote char (language specific) 507 */ 508 function singlequoteopening() { 509 } 510 511 /** 512 * Render a closing single quote char (language specific) 513 */ 514 function singlequoteclosing() { 515 } 516 517 /** 518 * Render an apostrophe char (language specific) 519 */ 520 function apostrophe() { 521 } 522 523 /** 524 * Render an opening double quote char (language specific) 525 */ 526 function doublequoteopening() { 527 } 528 529 /** 530 * Render an closinging double quote char (language specific) 531 */ 532 function doublequoteclosing() { 533 } 534 535 /** 536 * Render a CamelCase link 537 * 538 * @param string $link The link name 539 * @see http://en.wikipedia.org/wiki/CamelCase 540 */ 541 function camelcaselink($link) { 542 } 543 544 /** 545 * Render a page local link 546 * 547 * @param string $hash hash link identifier 548 * @param string $name name for the link 549 */ 550 function locallink($hash, $name = null) { 551 } 552 553 /** 554 * Render a wiki internal link 555 * 556 * @param string $link page ID to link to. eg. 'wiki:syntax' 557 * @param string|array $title name for the link, array for media file 558 */ 559 function internallink($link, $title = null) { 560 } 561 562 /** 563 * Render an external link 564 * 565 * @param string $link full URL with scheme 566 * @param string|array $title name for the link, array for media file 567 */ 568 function externallink($link, $title = null) { 569 } 570 571 /** 572 * Render the output of an RSS feed 573 * 574 * @param string $url URL of the feed 575 * @param array $params Finetuning of the output 576 */ 577 function rss($url, $params) { 578 } 579 580 /** 581 * Render an interwiki link 582 * 583 * You may want to use $this->_resolveInterWiki() here 584 * 585 * @param string $link original link - probably not much use 586 * @param string|array $title name for the link, array for media file 587 * @param string $wikiName indentifier (shortcut) for the remote wiki 588 * @param string $wikiUri the fragment parsed from the original link 589 */ 590 function interwikilink($link, $title = null, $wikiName, $wikiUri) { 591 } 592 593 /** 594 * Link to file on users OS 595 * 596 * @param string $link the link 597 * @param string|array $title name for the link, array for media file 598 */ 599 function filelink($link, $title = null) { 600 } 601 602 /** 603 * Link to windows share 604 * 605 * @param string $link the link 606 * @param string|array $title name for the link, array for media file 607 */ 608 function windowssharelink($link, $title = null) { 609 } 610 611 /** 612 * Render a linked E-Mail Address 613 * 614 * Should honor $conf['mailguard'] setting 615 * 616 * @param string $address Email-Address 617 * @param string|array $name name for the link, array for media file 618 */ 619 function emaillink($address, $name = null) { 620 } 621 622 /** 623 * Render an internal media file 624 * 625 * @param string $src media ID 626 * @param string $title descriptive text 627 * @param string $align left|center|right 628 * @param int $width width of media in pixel 629 * @param int $height height of media in pixel 630 * @param string $cache cache|recache|nocache 631 * @param string $linking linkonly|detail|nolink 632 */ 633 function internalmedia($src, $title = null, $align = null, $width = null, 634 $height = null, $cache = null, $linking = null) { 635 } 636 637 /** 638 * Render an external media file 639 * 640 * @param string $src full media URL 641 * @param string $title descriptive text 642 * @param string $align left|center|right 643 * @param int $width width of media in pixel 644 * @param int $height height of media in pixel 645 * @param string $cache cache|recache|nocache 646 * @param string $linking linkonly|detail|nolink 647 */ 648 function externalmedia($src, $title = null, $align = null, $width = null, 649 $height = null, $cache = null, $linking = null) { 650 } 651 652 /** 653 * Render a link to an internal media file 654 * 655 * @param string $src media ID 656 * @param string $title descriptive text 657 * @param string $align left|center|right 658 * @param int $width width of media in pixel 659 * @param int $height height of media in pixel 660 * @param string $cache cache|recache|nocache 661 */ 662 function internalmedialink($src, $title = null, $align = null, 663 $width = null, $height = null, $cache = null) { 664 } 665 666 /** 667 * Render a link to an external media file 668 * 669 * @param string $src media ID 670 * @param string $title descriptive text 671 * @param string $align left|center|right 672 * @param int $width width of media in pixel 673 * @param int $height height of media in pixel 674 * @param string $cache cache|recache|nocache 675 */ 676 function externalmedialink($src, $title = null, $align = null, 677 $width = null, $height = null, $cache = null) { 678 } 679 680 /** 681 * Start a table 682 * 683 * @param int $maxcols maximum number of columns 684 * @param int $numrows NOT IMPLEMENTED 685 * @param int $pos byte position in the original source 686 */ 687 function table_open($maxcols = null, $numrows = null, $pos = null) { 688 } 689 690 /** 691 * Close a table 692 * 693 * @param int $pos byte position in the original source 694 */ 695 function table_close($pos = null) { 696 } 697 698 /** 699 * Open a table header 700 */ 701 function tablethead_open() { 702 } 703 704 /** 705 * Close a table header 706 */ 707 function tablethead_close() { 708 } 709 710 /** 711 * Open a table body 712 */ 713 function tabletbody_open() { 714 } 715 716 /** 717 * Close a table body 718 */ 719 function tabletbody_close() { 720 } 721 722 /** 723 * Open a table footer 724 */ 725 function tabletfoot_open() { 726 } 727 728 /** 729 * Close a table footer 730 */ 731 function tabletfoot_close() { 732 } 733 734 /** 735 * Open a table row 736 */ 737 function tablerow_open() { 738 } 739 740 /** 741 * Close a table row 742 */ 743 function tablerow_close() { 744 } 745 746 /** 747 * Open a table header cell 748 * 749 * @param int $colspan 750 * @param string $align left|center|right 751 * @param int $rowspan 752 */ 753 function tableheader_open($colspan = 1, $align = null, $rowspan = 1) { 754 } 755 756 /** 757 * Close a table header cell 758 */ 759 function tableheader_close() { 760 } 761 762 /** 763 * Open a table cell 764 * 765 * @param int $colspan 766 * @param string $align left|center|right 767 * @param int $rowspan 768 */ 769 function tablecell_open($colspan = 1, $align = null, $rowspan = 1) { 770 } 771 772 /** 773 * Close a table cell 774 */ 775 function tablecell_close() { 776 } 777 778 #endregion 779 780 #region util functions, you probably won't need to reimplement them 781 782 /** 783 * Removes any Namespace from the given name but keeps 784 * casing and special chars 785 * 786 * @author Andreas Gohr <andi@splitbrain.org> 787 * 788 * @param string $name 789 * @return string 790 */ 791 function _simpleTitle($name) { 792 global $conf; 793 794 //if there is a hash we use the ancor name only 795 @list($name, $hash) = explode('#', $name, 2); 796 if($hash) return $hash; 797 798 if($conf['useslash']) { 799 $name = strtr($name, ';/', ';:'); 800 } else { 801 $name = strtr($name, ';', ':'); 802 } 803 804 return noNSorNS($name); 805 } 806 807 /** 808 * Resolve an interwikilink 809 * 810 * @param string $shortcut identifier for the interwiki link 811 * @param string $reference fragment that refers the content 812 * @param null|bool $exists reference which returns if an internal page exists 813 * @return string interwikilink 814 */ 815 function _resolveInterWiki(&$shortcut, $reference, &$exists = null) { 816 //get interwiki URL 817 if(isset($this->interwiki[$shortcut])) { 818 $url = $this->interwiki[$shortcut]; 819 } else { 820 // Default to Google I'm feeling lucky 821 $url = 'https://www.google.com/search?q={URL}&btnI=lucky'; 822 $shortcut = 'go'; 823 } 824 825 //split into hash and url part 826 $hash = strrchr($reference, '#'); 827 if($hash) { 828 $reference = substr($reference, 0, -strlen($hash)); 829 $hash = substr($hash, 1); 830 } 831 832 //replace placeholder 833 if(preg_match('#\{(URL|NAME|SCHEME|HOST|PORT|PATH|QUERY)\}#', $url)) { 834 //use placeholders 835 $url = str_replace('{URL}', rawurlencode($reference), $url); 836 //wiki names will be cleaned next, otherwise urlencode unsafe chars 837 $url = str_replace('{NAME}', ($url{0} === ':') ? $reference : 838 preg_replace_callback('/[[\\\\\]^`{|}#%]/', function($match) { 839 return rawurlencode($match[0]); 840 }, $reference), $url); 841 $parsed = parse_url($reference); 842 if (empty($parsed['scheme'])) $parsed['scheme'] = ''; 843 if (empty($parsed['host'])) $parsed['host'] = ''; 844 if (empty($parsed['port'])) $parsed['port'] = 80; 845 if (empty($parsed['path'])) $parsed['path'] = ''; 846 if (empty($parsed['query'])) $parsed['query'] = ''; 847 $url = strtr($url,[ 848 '{SCHEME}' => $parsed['scheme'], 849 '{HOST}' => $parsed['host'], 850 '{PORT}' => $parsed['port'], 851 '{PATH}' => $parsed['path'], 852 '{QUERY}' => $parsed['query'] , 853 ]); 854 } else { 855 //default 856 $url = $url.rawurlencode($reference); 857 } 858 //handle as wiki links 859 if($url{0} === ':') { 860 list($id, $urlparam) = explode('?', $url, 2); 861 $url = wl(cleanID($id), $urlparam); 862 $exists = page_exists($id); 863 } 864 if($hash) $url .= '#'.rawurlencode($hash); 865 866 return $url; 867 } 868 869 #endregion 870} 871 872 873//Setup VIM: ex: et ts=4 : 874