xref: /dokuwiki/inc/parser/renderer.php (revision 84c50c494ac3b4f524ce81304691d7fed3975b68)
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 $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     */
347    function listitem_open($level) {
348    }
349
350    /**
351     * Close a list item
352     */
353    function listitem_close() {
354    }
355
356    /**
357     * Start the content of a list item
358     */
359    function listcontent_open() {
360    }
361
362    /**
363     * Stop the content of a list item
364     */
365    function listcontent_close() {
366    }
367
368    /**
369     * Output unformatted $text
370     *
371     * Defaults to $this->cdata()
372     *
373     * @param string $text
374     */
375    function unformatted($text) {
376        $this->cdata($text);
377    }
378
379    /**
380     * Output inline PHP code
381     *
382     * If $conf['phpok'] is true this should evaluate the given code and append the result
383     * to $doc
384     *
385     * @param string $text The PHP code
386     */
387    function php($text) {
388    }
389
390    /**
391     * Output block level PHP code
392     *
393     * If $conf['phpok'] is true this should evaluate the given code and append the result
394     * to $doc
395     *
396     * @param string $text The PHP code
397     */
398    function phpblock($text) {
399    }
400
401    /**
402     * Output raw inline HTML
403     *
404     * If $conf['htmlok'] is true this should add the code as is to $doc
405     *
406     * @param string $text The HTML
407     */
408    function html($text) {
409    }
410
411    /**
412     * Output raw block-level HTML
413     *
414     * If $conf['htmlok'] is true this should add the code as is to $doc
415     *
416     * @param string $text The HTML
417     */
418    function htmlblock($text) {
419    }
420
421    /**
422     * Output preformatted text
423     *
424     * @param string $text
425     */
426    function preformatted($text) {
427    }
428
429    /**
430     * Start a block quote
431     */
432    function quote_open() {
433    }
434
435    /**
436     * Stop a block quote
437     */
438    function quote_close() {
439    }
440
441    /**
442     * Display text as file content, optionally syntax highlighted
443     *
444     * @param string $text text to show
445     * @param string $lang programming language to use for syntax highlighting
446     * @param string $file file path label
447     */
448    function file($text, $lang = null, $file = null) {
449    }
450
451    /**
452     * Display text as code content, optionally syntax highlighted
453     *
454     * @param string $text text to show
455     * @param string $lang programming language to use for syntax highlighting
456     * @param string $file file path label
457     */
458    function code($text, $lang = null, $file = null) {
459    }
460
461    /**
462     * Format an acronym
463     *
464     * Uses $this->acronyms
465     *
466     * @param string $acronym
467     */
468    function acronym($acronym) {
469    }
470
471    /**
472     * Format a smiley
473     *
474     * Uses $this->smiley
475     *
476     * @param string $smiley
477     */
478    function smiley($smiley) {
479    }
480
481    /**
482     * Format an entity
483     *
484     * Entities are basically small text replacements
485     *
486     * Uses $this->entities
487     *
488     * @param string $entity
489     */
490    function entity($entity) {
491    }
492
493    /**
494     * Typographically format a multiply sign
495     *
496     * Example: ($x=640, $y=480) should result in "640×480"
497     *
498     * @param string|int $x first value
499     * @param string|int $y second value
500     */
501    function multiplyentity($x, $y) {
502    }
503
504    /**
505     * Render an opening single quote char (language specific)
506     */
507    function singlequoteopening() {
508    }
509
510    /**
511     * Render a closing single quote char (language specific)
512     */
513    function singlequoteclosing() {
514    }
515
516    /**
517     * Render an apostrophe char (language specific)
518     */
519    function apostrophe() {
520    }
521
522    /**
523     * Render an opening double quote char (language specific)
524     */
525    function doublequoteopening() {
526    }
527
528    /**
529     * Render an closinging double quote char (language specific)
530     */
531    function doublequoteclosing() {
532    }
533
534    /**
535     * Render a CamelCase link
536     *
537     * @param string $link The link name
538     * @see http://en.wikipedia.org/wiki/CamelCase
539     */
540    function camelcaselink($link) {
541    }
542
543    /**
544     * Render a page local link
545     *
546     * @param string $hash hash link identifier
547     * @param string $name name for the link
548     */
549    function locallink($hash, $name = null) {
550    }
551
552    /**
553     * Render a wiki internal link
554     *
555     * @param string       $link  page ID to link to. eg. 'wiki:syntax'
556     * @param string|array $title name for the link, array for media file
557     */
558    function internallink($link, $title = null) {
559    }
560
561    /**
562     * Render an external link
563     *
564     * @param string       $link  full URL with scheme
565     * @param string|array $title name for the link, array for media file
566     */
567    function externallink($link, $title = null) {
568    }
569
570    /**
571     * Render the output of an RSS feed
572     *
573     * @param string $url    URL of the feed
574     * @param array  $params Finetuning of the output
575     */
576    function rss($url, $params) {
577    }
578
579    /**
580     * Render an interwiki link
581     *
582     * You may want to use $this->_resolveInterWiki() here
583     *
584     * @param string       $link     original link - probably not much use
585     * @param string|array $title    name for the link, array for media file
586     * @param string       $wikiName indentifier (shortcut) for the remote wiki
587     * @param string       $wikiUri  the fragment parsed from the original link
588     */
589    function interwikilink($link, $title = null, $wikiName, $wikiUri) {
590    }
591
592    /**
593     * Link to file on users OS
594     *
595     * @param string       $link  the link
596     * @param string|array $title name for the link, array for media file
597     */
598    function filelink($link, $title = null) {
599    }
600
601    /**
602     * Link to windows share
603     *
604     * @param string       $link  the link
605     * @param string|array $title name for the link, array for media file
606     */
607    function windowssharelink($link, $title = null) {
608    }
609
610    /**
611     * Render a linked E-Mail Address
612     *
613     * Should honor $conf['mailguard'] setting
614     *
615     * @param string $address Email-Address
616     * @param string|array $name name for the link, array for media file
617     */
618    function emaillink($address, $name = null) {
619    }
620
621    /**
622     * Render an internal media file
623     *
624     * @param string $src     media ID
625     * @param string $title   descriptive text
626     * @param string $align   left|center|right
627     * @param int    $width   width of media in pixel
628     * @param int    $height  height of media in pixel
629     * @param string $cache   cache|recache|nocache
630     * @param string $linking linkonly|detail|nolink
631     */
632    function internalmedia($src, $title = null, $align = null, $width = null,
633                           $height = null, $cache = null, $linking = null) {
634    }
635
636    /**
637     * Render an external media file
638     *
639     * @param string $src     full media URL
640     * @param string $title   descriptive text
641     * @param string $align   left|center|right
642     * @param int    $width   width of media in pixel
643     * @param int    $height  height of media in pixel
644     * @param string $cache   cache|recache|nocache
645     * @param string $linking linkonly|detail|nolink
646     */
647    function externalmedia($src, $title = null, $align = null, $width = null,
648                           $height = null, $cache = null, $linking = null) {
649    }
650
651    /**
652     * Render a link to an internal media file
653     *
654     * @param string $src     media ID
655     * @param string $title   descriptive text
656     * @param string $align   left|center|right
657     * @param int    $width   width of media in pixel
658     * @param int    $height  height of media in pixel
659     * @param string $cache   cache|recache|nocache
660     */
661    function internalmedialink($src, $title = null, $align = null,
662                               $width = null, $height = null, $cache = null) {
663    }
664
665    /**
666     * Render a link to an external media file
667     *
668     * @param string $src     media ID
669     * @param string $title   descriptive text
670     * @param string $align   left|center|right
671     * @param int    $width   width of media in pixel
672     * @param int    $height  height of media in pixel
673     * @param string $cache   cache|recache|nocache
674     */
675    function externalmedialink($src, $title = null, $align = null,
676                               $width = null, $height = null, $cache = null) {
677    }
678
679    /**
680     * Start a table
681     *
682     * @param int $maxcols maximum number of columns
683     * @param int $numrows NOT IMPLEMENTED
684     * @param int $pos     byte position in the original source
685     */
686    function table_open($maxcols = null, $numrows = null, $pos = null) {
687    }
688
689    /**
690     * Close a table
691     *
692     * @param int $pos byte position in the original source
693     */
694    function table_close($pos = null) {
695    }
696
697    /**
698     * Open a table header
699     */
700    function tablethead_open() {
701    }
702
703    /**
704     * Close a table header
705     */
706    function tablethead_close() {
707    }
708
709    /**
710     * Open a table row
711     */
712    function tablerow_open() {
713    }
714
715    /**
716     * Close a table row
717     */
718    function tablerow_close() {
719    }
720
721    /**
722     * Open a table header cell
723     *
724     * @param int    $colspan
725     * @param string $align left|center|right
726     * @param int    $rowspan
727     */
728    function tableheader_open($colspan = 1, $align = null, $rowspan = 1) {
729    }
730
731    /**
732     * Close a table header cell
733     */
734    function tableheader_close() {
735    }
736
737    /**
738     * Open a table cell
739     *
740     * @param int    $colspan
741     * @param string $align left|center|right
742     * @param int    $rowspan
743     */
744    function tablecell_open($colspan = 1, $align = null, $rowspan = 1) {
745    }
746
747    /**
748     * Close a table cell
749     */
750    function tablecell_close() {
751    }
752
753    #endregion
754
755    #region util functions, you probably won't need to reimplement them
756
757    /**
758     * Removes any Namespace from the given name but keeps
759     * casing and special chars
760     *
761     * @author Andreas Gohr <andi@splitbrain.org>
762     */
763    function _simpleTitle($name) {
764        global $conf;
765
766        //if there is a hash we use the ancor name only
767        @list($name, $hash) = explode('#', $name, 2);
768        if($hash) return $hash;
769
770        if($conf['useslash']) {
771            $name = strtr($name, ';/', ';:');
772        } else {
773            $name = strtr($name, ';', ':');
774        }
775
776        return noNSorNS($name);
777    }
778
779    /**
780     * Resolve an interwikilink
781     */
782    function _resolveInterWiki(&$shortcut, $reference, &$exists = null) {
783        //get interwiki URL
784        if(isset($this->interwiki[$shortcut])) {
785            $url = $this->interwiki[$shortcut];
786        } else {
787            // Default to Google I'm feeling lucky
788            $url      = 'http://www.google.com/search?q={URL}&amp;btnI=lucky';
789            $shortcut = 'go';
790        }
791
792        //split into hash and url part
793        @list($reference, $hash) = explode('#', $reference, 2);
794
795        //replace placeholder
796        if(preg_match('#\{(URL|NAME|SCHEME|HOST|PORT|PATH|QUERY)\}#', $url)) {
797            //use placeholders
798            $url    = str_replace('{URL}', rawurlencode($reference), $url);
799            $url    = str_replace('{NAME}', $reference, $url);
800            $parsed = parse_url($reference);
801            if(!$parsed['port']) $parsed['port'] = 80;
802            $url = str_replace('{SCHEME}', $parsed['scheme'], $url);
803            $url = str_replace('{HOST}', $parsed['host'], $url);
804            $url = str_replace('{PORT}', $parsed['port'], $url);
805            $url = str_replace('{PATH}', $parsed['path'], $url);
806            $url = str_replace('{QUERY}', $parsed['query'], $url);
807        } else {
808            //default
809            $url = $url.rawurlencode($reference);
810        }
811        //handle as wiki links
812        if($url{0} === ':') {
813            list($id, $urlparam) = explode('?', $url, 2);
814            $url    = wl(cleanID($id), $urlparam);
815            $exists = page_exists($id);
816        }
817        if($hash) $url .= '#'.rawurlencode($hash);
818
819        return $url;
820    }
821
822    #endregion
823}
824
825
826//Setup VIM: ex: et ts=4 :
827