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