xref: /plugin/diagrams/syntax/mediafile.php (revision babd140584abb7888a7f4197efb774857ff7d5e8)
1<?php
2
3use dokuwiki\plugin\diagrams\Diagrams;
4
5/**
6 * Class syntax_plugin_diagrams
7 */
8class syntax_plugin_diagrams_mediafile extends DokuWiki_Syntax_Plugin
9{
10
11    /**
12     * @inheritdoc
13     */
14    public function getType()
15    {
16        return 'substition';
17    }
18
19    /**
20     * @inheritdoc
21     */
22    public function getSort()
23    {
24        return 319;
25    }
26
27    /**
28     * @inheritdoc
29     */
30    public function connectTo($mode)
31    {
32        // only register if mediafile mode is enabled
33        if (!($this->getConf('mode') & Diagrams::MODE_MEDIA)) return;
34
35        // grab all SVG images
36        $this->Lexer->addSpecialPattern('\{\{[^\}]+(?:\.svg)[^\}]*?\}\}', $mode, 'plugin_diagrams_mediafile');
37    }
38
39    /**
40     * Parse SVG syntax into media data
41     *
42     * @param string $match
43     * @param int $state
44     * @param int $pos
45     * @param Doku_Handler $handler
46     * @return array|bool
47     */
48    public function handle($match, $state, $pos, Doku_Handler $handler)
49    {
50        $data = Doku_Handler_Parse_Media($match);
51
52        /** @var helper_plugin_diagrams $helper */
53        $helper = plugin_load('helper', 'diagrams');
54        if (!($data['type'] === 'internalmedia' && $helper->isDiagramFile(mediaFN($data['src'])))) {
55            // This is not a local diagrams file, but some other SVG media file
56            $handler->media($match, $state, $pos);
57            return false;
58        }
59
60        $data['url'] = ml($data['src'], ['cache' => 'nocache'], true, '&');
61        return $data;
62    }
63
64    /**
65     * Handle rewrites made by the move plugin
66     *
67     * @param string $match
68     * @param int $state
69     * @param int $pos
70     * @param string $plugin
71     * @param helper_plugin_move_handler $handler
72     * @return void
73     */
74    public function handleMove($match, $state, $pos, $plugin, $handler)
75    {
76        if ($plugin !== 'diagrams_mediafile') return;
77
78        $handler->media($match, $state, $pos);
79    }
80
81    /**
82     * Render the diagram SVG as <object> instead of <img> to allow links,
83     * except when rendering to a PDF
84     *
85     * @param string $format
86     * @param Doku_Renderer $renderer
87     * @param array $data
88     * @return bool
89     */
90    public function render($format, Doku_Renderer $renderer, $data)
91    {
92        global $conf;
93
94        if ($format === 'metadata') {
95            $renderer->internalmedia($data['src']);
96            return true;
97        }
98        if ($format !== 'xhtml') {
99            return false;
100        }
101
102        if (auth_quickaclcheck(cleanID($data['src'])) < AUTH_READ) return false;
103
104        // check for cached PNG
105        $cachefile = $this->getCachedPNG($data);
106
107        if (is_a($renderer, 'renderer_plugin_dw2pdf')) {
108            $imageAttributes = [
109                'class' => 'media',
110                'width' => empty($data['width']) ? '' : $data['width'],
111                'height' => empty($data['height']) ? '' : $data['height'],
112                'title' => $data['title'] ?? '',
113                'alt' => $data['title'] ?? '',
114                'align' => $data['align'],
115                'src' => $data['url'],
116            ];
117
118            // if a PNG cache exists, use it instead of the real URL
119            // or display error if PNG of embedded diagram is missing
120            if ($cachefile) {
121                $imageAttributes['src'] = 'dw2pdf://' . $cachefile;
122            } elseif ($this->getConf('pngcache') && is_a($this, 'syntax_plugin_diagrams_embed')) {
123                $renderer->doc .= $this->getLang('errorMissingPNG');
124                return false;
125            }
126
127            $renderer->doc .= '<img ' . buildAttributes($imageAttributes) . '/>';
128        } else {
129            $wrapperAttributes = [];
130            $wrapperAttributes['title'] = $data['title'] ?? '';
131            $wrapperAttributes['class'] = 'media diagrams-svg-wrapper media' . $data['align'];
132
133            $imageAttributes = [];
134            $imageAttributes['class'] = 'diagrams-svg';
135            $imageAttributes['data'] = $data['url'];
136            $imageAttributes['data-id'] = cleanID($data['src'] ?? '');
137            $imageAttributes['type'] = 'image/svg+xml';
138            $imageAttributes['data-pos'] = $data['pos'] ?? '';
139            $imageAttributes['data-len'] = $data['len'] ?? '';
140            $imageAttributes['width'] = empty($data['width']) ? '' : $data['width'];
141            $imageAttributes['height'] = empty($data['height']) ? '' : $data['height'];
142
143            if ($cachefile) {
144                // strip cache dir and our cache extension from data attribute
145                $imageAttributes['data-pngcache'] = str_replace([$conf['cachedir'], Diagrams::CACHE_EXT], '', $cachefile);
146            }
147
148            $image = sprintf('<object %s><span class="diagrams-alt">' . hsc($wrapperAttributes['title']) . '</span></object>', buildAttributes($imageAttributes, true));
149            // wrapper for action buttons
150            $actionButtons = '<div class="diagrams-buttons"></div>';
151            $wrapper = sprintf('<div %s>%s%s</div>', buildAttributes($wrapperAttributes, true), $image, $actionButtons);
152            $renderer->doc .= $wrapper;
153        }
154
155        return true;
156    }
157
158    /**
159     * PNG cache file without extension, if caching is enabled and file exists.
160     * Returns an empty string on older revisions (checking $REV), because
161     * PNG caching does not support versioning.
162     *
163     * @param array $data
164     * @return string
165     */
166    protected function getCachedPNG($data)
167    {
168        global $REV;
169
170        if (!$this->getConf('pngcache') || $REV) return '';
171
172        if (empty($data['svg'])) {
173            $data['svg'] = file_get_contents(mediaFN($data['src']));
174        }
175        $cachefile = getCacheName($data['svg'], Diagrams::CACHE_EXT);
176        if (file_exists($cachefile)) return $cachefile;
177
178        return '';
179    }
180}
181