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