renderer.php 21 KB

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