xref: /plugin/diagrams/syntax/embed.php (revision 20761fcf3f1fcd57efaa7d19e2cab0a62c285345)
1<?php
2
3use dokuwiki\plugin\diagrams\Diagrams;
4
5/**
6 * DokuWiki Plugin diagrams (Syntax Component)
7 *
8 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
9 * @author  Innovakom + CosmoCode <dokuwiki@cosmocode.de>
10 */
11class syntax_plugin_diagrams_embed extends syntax_plugin_diagrams_mediafile
12{
13    /** @var int count the current embedded diagram */
14    protected $count = 0;
15
16    /** @inheritDoc */
17    public function connectTo($mode)
18    {
19        // only register if embed mode is enabled
20        if (!($this->getConf('mode') & Diagrams::MODE_EMBED)) return;
21        $this->Lexer->addSpecialPattern('<diagram(?: .*?)?>.*?(?:</diagram>)', $mode, 'plugin_diagrams_embed');
22    }
23
24    /** @inheritDoc */
25    public function handle($match, $state, $pos, Doku_Handler $handler)
26    {
27        [$open, $rest] = sexplode('>', $match, 2);
28        $params = substr($open, 9);
29        $svg = substr($rest, 0, -10);
30
31        // embed positions
32        $svglen = strlen($svg);
33        $svgpos = $pos + strpos($match, '>');
34
35        /** @var helper_plugin_diagrams $helper */
36        $helper = plugin_load('helper', 'diagrams');
37        if (!$helper->isDiagram($svg)) return false;
38
39        $data = [
40            'svg' => $svg,
41            'title' => '',
42            'align' => '',
43            'width' => '',
44            'height' => '',
45            'pos' => $svgpos,
46            'len' => $svglen,
47        ];
48
49        if (preg_match('/\|(.*)/', $params, $matches)) {
50            $data['title'] = $matches[1];
51            $params = str_replace($matches[0], '', $params);
52        }
53        if (preg_match('/\b(left|right|center)\b/', $params, $matches)) {
54            $data['align'] = $matches[1];
55        }
56        if (preg_match('/\b(\d+)x(\d+)\b/', $params, $matches)) {
57            $data['width'] = (int)$matches[1];
58            $data['height'] = (int)$matches[2];
59        }
60
61        return $data;
62    }
63
64    /** @inheritDoc */
65    public function render($format, Doku_Renderer $renderer, $data)
66    {
67        if (!$data) return false;
68        global $ID;
69        global $ACT;
70        global $INPUT;
71        global $REV;
72
73        switch ($format) {
74            case 'xhtml':
75                if (act_clean($ACT) !== 'preview' && page_exists($ID)) {
76                    // this is "normal" rendering, we reference the diagram through the export
77                    // this applies the same CSP as media files and will also show the exact behaviours
78                    $data['url'] = wl($ID, ['do' => 'export_diagrams', 'svg' => $this->count++, 'rev' => $REV], true, '&');
79                } else {
80                    // we're in preview and the diagram may not have been saved, yet. So we
81                    // reference it as data uri to prevent cross-origin access XSS
82                    $data['url'] = 'data:image/svg+xml;base64,' . base64_encode($data['svg']);
83                }
84
85                parent::render($format, $renderer, $data);
86                return true;
87            case 'diagrams':
88                // This exports a single SVG during the export_diagrams action
89                if ($INPUT->int('svg') === $this->count++) {
90                    $renderer->doc = $data['svg'];
91                }
92                return true;
93        }
94        return false;
95    }
96
97
98}
99
100