1<?php
2
3// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
4// phpcs:disable PSR2.Methods.MethodDeclaration.Underscore
5
6use dokuwiki\Extension\SyntaxPlugin;
7use dokuwiki\File\PageResolver;
8
9/**
10 * Renderer for preparing data for embedding
11 *
12 * Based on the text and markdown renderers
13 *
14 * @todo table handling is not perfect
15 * @author Michael Hamann <michael@content-space.de>
16 * @author Todd Augsburger <todd@rollerorgans.com>
17 * @author i-net software <tools@inetsoftware.de>
18 * @link https://www.dokuwiki.org/plugin:text
19 * @link https://www.dokuwiki.org/plugin:dw2markdown
20 */
21class renderer_plugin_aichat extends Doku_Renderer_xhtml
22{
23    /** @var array The stack of list types */
24    private $listMode = [];
25
26    /** @var int Number of table columns */
27    private $tableColumns = 0;
28
29    /** @inheritdoc */
30    public function getFormat()
31    {
32        return 'aichat';
33    }
34
35    /** @inheritdoc */
36    public function startSectionEdit($start, $data, $title = null)
37    {
38    }
39
40    /** @inheritdoc */
41    public function finishSectionEdit($end = null, $hid = null)
42    {
43    }
44
45    /**
46     * @inheritdoc
47     * Use specific text support if available, otherwise use xhtml renderer and strip tags
48     */
49    public function plugin($name, $data, $state = '', $match = '')
50    {
51        /** @var SyntaxPlugin $plugin */
52        $plugin = plugin_load('syntax', $name);
53        if ($plugin === null) return;
54
55        if (
56            !$plugin->render($this->getFormat(), $this, $data) &&
57            !$plugin->render('text', $this, $data) &&
58            !$plugin->render('markdown', $this, $data)
59        ) {
60            // plugin does not support any of the text formats, so use stripped-down xhtml
61            $tmpData = $this->doc;
62            $this->doc = '';
63            if ($plugin->render('xhtml', $this, $data) && ($this->doc !== '')) {
64                $pluginoutput = $this->doc;
65                $this->doc = $tmpData . DOKU_LF . trim(strip_tags($pluginoutput)) . DOKU_LF;
66            } else {
67                $this->doc = $tmpData;
68            }
69        }
70    }
71
72    /** @inheritdoc */
73    public function document_start()
74    {
75        global $ID;
76
77        $this->doc = '';
78        $metaheader = [];
79        $metaheader['Content-Type'] = 'text/plain; charset=utf-8';
80        $meta = [];
81        $meta['format']['aichat'] = $metaheader;
82        p_set_metadata($ID, $meta);
83    }
84
85    /** @inheritdoc */
86    public function document_end()
87    {
88        $this->doc = preg_replace("/(\r?\n){3,}/", "\n\n", $this->doc);
89        $this->doc = ltrim($this->doc); // remove leading space and empty lines
90
91        // remove ignored parts
92        $regex = $this->getConf('ignoreRegex');
93        if($regex) {
94            $this->doc = preg_replace('/' . $regex . '/i', '', $this->doc);
95        }
96    }
97
98    /** @inheritdoc */
99    public function header($text, $level, $pos, $returnonly = false)
100    {
101        $this->doc .= str_repeat("#", $level) . ' ' . $text . DOKU_LF;
102    }
103
104    /** @inheritdoc */
105    public function section_open($level)
106    {
107        $this->doc .= DOKU_LF;
108    }
109
110    /** @inheritdoc */
111    public function section_close()
112    {
113        $this->doc .= DOKU_LF;
114    }
115
116    /** @inheritdoc */
117    public function cdata($text)
118    {
119        $this->doc .= $text;
120    }
121
122    /** @inheritdoc */
123    public function p_open()
124    {
125        $this->doc .= DOKU_LF;
126    }
127
128    /** @inheritdoc */
129    public function p_close()
130    {
131        $this->doc .= DOKU_LF;
132    }
133
134    /** @inheritdoc */
135    public function linebreak()
136    {
137        $this->doc .= DOKU_LF . DOKU_LF;
138    }
139
140    /** @inheritdoc */
141    public function hr()
142    {
143        $this->doc .= '----' . DOKU_LF;
144    }
145
146    /** @inheritdoc */
147    public function strong_open()
148    {
149    }
150
151    /** @inheritdoc */
152    public function strong_close()
153    {
154    }
155
156    /** @inheritdoc */
157    public function emphasis_open()
158    {
159    }
160
161    /** @inheritdoc */
162    public function emphasis_close()
163    {
164    }
165
166    /** @inheritdoc */
167    public function underline_open()
168    {
169    }
170
171    /** @inheritdoc */
172    public function underline_close()
173    {
174    }
175
176    /** @inheritdoc */
177    public function monospace_open()
178    {
179    }
180
181    /** @inheritdoc */
182    public function monospace_close()
183    {
184    }
185
186    /** @inheritdoc */
187    public function subscript_open()
188    {
189    }
190
191    /** @inheritdoc */
192    public function subscript_close()
193    {
194    }
195
196    /** @inheritdoc */
197    public function superscript_open()
198    {
199    }
200
201    /** @inheritdoc */
202    public function superscript_close()
203    {
204    }
205
206    /** @inheritdoc */
207    public function deleted_open()
208    {
209    }
210
211    /** @inheritdoc */
212    public function deleted_close()
213    {
214    }
215
216    /** @inheritdoc */
217    public function footnote_open()
218    {
219        $this->doc .= ' ((';
220    }
221
222    /** @inheritdoc */
223    public function footnote_close()
224    {
225        $this->doc .= '))';
226    }
227
228    /** @inheritdoc */
229    public function listu_open($classes = null)
230    {
231        if ($this->listMode === []) {
232            $this->doc .= DOKU_LF;
233        }
234        $this->listMode[] = '*';
235    }
236
237    /** @inheritdoc */
238    public function listu_close()
239    {
240        array_pop($this->listMode);
241        if ($this->listMode === []) {
242            $this->doc .= DOKU_LF;
243        }
244    }
245
246    /** @inheritdoc */
247    public function listo_open($classes = null)
248    {
249        if ($this->listMode === []) {
250            $this->doc .= DOKU_LF;
251        }
252        $this->listMode[] = '1.';
253    }
254
255    /** @inheritdoc */
256    public function listo_close()
257    {
258        array_pop($this->listMode);
259        if ($this->listMode === []) {
260            $this->doc .= DOKU_LF;
261        }
262    }
263
264    /** @inheritdoc */
265    public function listitem_open($level, $node = false)
266    {
267        $this->doc .= str_repeat(' ', $level * 2) . $this->listMode[count($this->listMode) - 1];
268    }
269
270    /** @inheritdoc */
271    public function listitem_close()
272    {
273    }
274
275
276    /** @inheritdoc */
277    public function listcontent_open()
278    {
279    }
280
281    /** @inheritdoc */
282    public function listcontent_close()
283    {
284        $this->doc .= DOKU_LF;
285    }
286
287    /** @inheritdoc */
288    public function unformatted($text)
289    {
290        $this->doc .= $text;
291    }
292
293    /** @inheritdoc */
294    public function quote_open()
295    {
296        $this->doc .= '>>>';
297    }
298
299    /** @inheritdoc */
300    public function quote_close()
301    {
302        $this->doc .= '<<<' . DOKU_LF;
303    }
304
305    /** @inheritdoc */
306    public function preformatted($text)
307    {
308        $this->code($text);
309    }
310
311    /** @inheritdoc */
312    public function file($text, $language = null, $filename = null, $options = null)
313    {
314        $this->code($text, $language, $filename, $options);
315    }
316
317    /** @inheritdoc */
318    public function code($text, $language = null, $filename = null, $options = null)
319    {
320        $this->doc .= DOKU_LF . '```' . ($language ?? '') . DOKU_LF . trim($text) . DOKU_LF . '```' . DOKU_LF;
321    }
322
323    /** @inheritdoc */
324    public function acronym($acronym)
325    {
326        if (array_key_exists($acronym, $this->acronyms)) {
327            $title = $this->acronyms[$acronym];
328            $this->doc .= $acronym . ' (' . $title . ')';
329        } else {
330            $this->doc .= $acronym;
331        }
332    }
333
334    /** @inheritdoc */
335    public function smiley($smiley)
336    {
337        $this->doc .= $smiley;
338    }
339
340    /** @inheritdoc */
341    public function entity($entity)
342    {
343        if (array_key_exists($entity, $this->entities)) {
344            $this->doc .= $this->entities[$entity];
345        } else {
346            $this->doc .= $entity;
347        }
348    }
349
350    /** @inheritdoc */
351    public function multiplyentity($x, $y)
352    {
353        $this->doc .= $x . 'x' . $y;
354    }
355
356    /** @inheritdoc */
357    public function singlequoteopening()
358    {
359        global $lang;
360        $this->doc .= $lang['singlequoteopening'];
361    }
362
363    /** @inheritdoc */
364    public function singlequoteclosing()
365    {
366        global $lang;
367        $this->doc .= $lang['singlequoteclosing'];
368    }
369
370    /** @inheritdoc */
371    public function apostrophe()
372    {
373        global $lang;
374        $this->doc .= $lang['apostrophe'];
375    }
376
377    /** @inheritdoc */
378    public function doublequoteopening()
379    {
380        global $lang;
381        $this->doc .= $lang['doublequoteopening'];
382    }
383
384    /** @inheritdoc */
385    public function doublequoteclosing()
386    {
387        global $lang;
388        $this->doc .= $lang['doublequoteclosing'];
389    }
390
391    /** @inheritdoc */
392    public function camelcaselink($link, $returnonly = false)
393    {
394        $this->internallink($link, $link);
395    }
396
397    /** @inheritdoc */
398    public function locallink($hash, $name = null, $returnonly = false)
399    {
400        $name = $this->_getLinkTitle($name, $hash, $isImage);
401        $this->doc .= $name;
402    }
403
404    /** @inheritdoc */
405    public function internallink($id, $name = null, $search = null, $returnonly = false, $linktype = 'content')
406    {
407        global $ID;
408        // default name is based on $id as given
409        $default = $this->_simpleTitle($id);
410        $resolver = new PageResolver($ID);
411        $id = $resolver->resolveId($id);
412
413        $name = $this->_getLinkTitle($name, $default, $isImage, $id, $linktype);
414        if ($returnonly) {
415            return $name;
416        }
417        $this->doc .= $name;
418        return null;
419    }
420
421    /** @inheritdoc */
422    public function externallink($url, $name = null, $returnonly = false)
423    {
424        $title = $this->_getLinkTitle($name, $url, $isImage);
425        if ($title != $url) {
426            $this->doc .= "[$title]($url)";
427        } else {
428            $this->doc .= $title;
429        }
430    }
431
432    /** @inheritdoc */
433    public function interwikilink($match, $name, $wikiName, $wikiUri, $returnonly = false)
434    {
435        $this->doc .= $this->_getLinkTitle($name, $wikiUri, $isImage);
436    }
437
438    /** @inheritdoc */
439    public function windowssharelink($url, $name = null, $returnonly = false)
440    {
441        $this->doc .= $this->_getLinkTitle($name, $url, $isImage);
442    }
443
444    /** @inheritdoc */
445    public function emaillink($address, $name = null, $returnonly = false)
446    {
447        $name = $this->_getLinkTitle($name, '', $isImage);
448        $address = html_entity_decode(obfuscate($address), ENT_QUOTES, 'UTF-8');
449        if (empty($name)) {
450            $name = $address;
451        }
452        $this->doc .= $name;
453    }
454
455    /** @inheritdoc */
456    public function internalmedia(
457        $src,
458        $title = null,
459        $align = null,
460        $width = null,
461        $height = null,
462        $cache = null,
463        $linking = null,
464        $return = false
465    ) {
466        $this->doc .= $title;
467    }
468
469    /** @inheritdoc */
470    public function externalmedia(
471        $src,
472        $title = null,
473        $align = null,
474        $width = null,
475        $height = null,
476        $cache = null,
477        $linking = null,
478        $return = false
479    ) {
480        $this->doc .= $title;
481    }
482
483    /** @inheritdoc */
484    public function rss($url, $params)
485    {
486    }
487
488    /** @inheritdoc */
489    public function table_open($maxcols = null, $numrows = null, $pos = null, $classes = null)
490    {
491    }
492
493    /** @inheritdoc */
494    public function table_close($pos = null)
495    {
496        $this->doc .= DOKU_LF;
497    }
498
499    /** @inheritdoc */
500    public function tablethead_open()
501    {
502        $this->tableColumns = 0;
503        $this->doc .= DOKU_LF; // . '|';
504    }
505
506    /** @inheritdoc */
507    public function tablethead_close()
508    {
509        $this->doc .= '|' . str_repeat('---|', $this->tableColumns) . DOKU_LF;
510    }
511
512    /** @inheritdoc */
513    public function tabletbody_open()
514    {
515    }
516
517    /** @inheritdoc */
518    public function tabletbody_close()
519    {
520    }
521
522    /** @inheritdoc */
523    public function tabletfoot_open()
524    {
525    }
526
527    /** @inheritdoc */
528    public function tabletfoot_close()
529    {
530    }
531
532    /** @inheritdoc */
533    public function tablerow_open($classes = null)
534    {
535    }
536
537    /** @inheritdoc */
538    public function tablerow_close()
539    {
540        $this->doc .= '|' . DOKU_LF;
541    }
542
543    /** @inheritdoc */
544    public function tableheader_open($colspan = 1, $align = null, $rowspan = 1, $classes = null)
545    {
546        $this->doc .= str_repeat('|', $colspan);
547        $this->tableColumns += $colspan;
548    }
549
550    /** @inheritdoc */
551    public function tableheader_close()
552    {
553    }
554
555    /** @inheritdoc */
556    public function tablecell_open($colspan = 1, $align = null, $rowspan = 1, $classes = null)
557    {
558        $this->doc .= str_repeat('|', $colspan);
559    }
560
561    /** @inheritdoc */
562    public function tablecell_close()
563    {
564    }
565
566    /** @inheritdoc */
567    public function _getLinkTitle($title, $default, &$isImage, $id = null, $linktype = 'content')
568    {
569        $isImage = false;
570        if (is_array($title)) {
571            $isImage = true;
572            if (!is_null($default) && ($default != $title['title']))
573                return $default . " " . $title['title'];
574            else return $title['title'];
575        } elseif (is_null($title) || trim($title) == '') {
576            if (useHeading($linktype) && $id) {
577                $heading = p_get_first_heading($id);
578                if ($heading) {
579                    return $this->_xmlEntities($heading);
580                }
581            }
582            return $this->_xmlEntities($default);
583        } else {
584            return $this->_xmlEntities($title);
585        }
586    }
587
588    /** @inheritdoc */
589    public function _xmlEntities($string)
590    {
591        return $string; // nothing to do for text
592    }
593
594    /** @inheritdoc */
595    public function _formatLink($link)
596    {
597        if (!empty($link['name'])) {
598            return $link['name'];
599        } elseif (!empty($link['title'])) {
600            return $link['title'];
601        }
602        return $link['url'];
603    }
604}
605