1<?php 2 3 4use ComboStrap\AnalyticsDocument; 5use ComboStrap\CallStack; 6use ComboStrap\DokuFs; 7use ComboStrap\DokuPath; 8use ComboStrap\Image; 9use ComboStrap\InternetPath; 10use ComboStrap\LogUtility; 11use ComboStrap\MediaLink; 12use ComboStrap\Metadata; 13use ComboStrap\PagePath; 14use ComboStrap\Path; 15use ComboStrap\PluginUtility; 16use ComboStrap\ThirdPartyPlugins; 17 18 19require_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 20 21 22/** 23 * Media 24 * 25 * Takes over the {@link \dokuwiki\Parsing\ParserMode\Media media mode} 26 * that is processed by {@link Doku_Handler_Parse_Media} 27 * 28 * 29 * 30 * It can be a internal / external media 31 * 32 * 33 * See: 34 * https://developers.google.com/search/docs/advanced/guidelines/google-images 35 */ 36class syntax_plugin_combo_media extends DokuWiki_Syntax_Plugin 37{ 38 39 40 const TAG = "media"; 41 42 /** 43 * Used in the move plugin 44 * !!! The two last word of the plugin class !!! 45 */ 46 const COMPONENT = 'combo_' . self::TAG; 47 48 49 /** 50 * Found at {@link \dokuwiki\Parsing\ParserMode\Media} 51 */ 52 const MEDIA_PATTERN = "\{\{(?:[^>\}]|(?:\}[^\}]))+\}\}"; 53 54 /** 55 * Enable or disable the image 56 */ 57 const CONF_IMAGE_ENABLE = "imageEnable"; 58 59 /** 60 * Svg Rendering error 61 */ 62 const SVG_RENDERING_ERROR_CLASS = "combo-svg-rendering-error"; 63 64 65 /** 66 * @param $attributes 67 * @param renderer_plugin_combo_analytics $renderer 68 */ 69 public static function updateStatistics($attributes, renderer_plugin_combo_analytics $renderer) 70 { 71 $media = MediaLink::createFromCallStackArray($attributes); 72 $renderer->stats[AnalyticsDocument::MEDIA_COUNT]++; 73 $scheme = $media->getMedia()->getPath()->getScheme(); 74 switch ($scheme) { 75 case DokuFs::SCHEME: 76 $renderer->stats[AnalyticsDocument::INTERNAL_MEDIA_COUNT]++; 77 if (!$media->getMedia()->exists()) { 78 $renderer->stats[AnalyticsDocument::INTERNAL_BROKEN_MEDIA_COUNT]++; 79 } 80 break; 81 case InternetPath::scheme: 82 $renderer->stats[AnalyticsDocument::EXTERNAL_MEDIA_COUNT]++; 83 break; 84 } 85 } 86 87 88 function getType() 89 { 90 return 'formatting'; 91 } 92 93 /** 94 * How Dokuwiki will add P element 95 * 96 * * 'normal' - The plugin can be used inside paragraphs (inline) 97 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 98 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 99 * 100 * @see DokuWiki_Syntax_Plugin::getPType() 101 */ 102 function getPType() 103 { 104 /** 105 * An image is not a block (it can be inside paragraph) 106 */ 107 return 'normal'; 108 } 109 110 function getAllowedTypes() 111 { 112 return array('substition', 'formatting', 'disabled'); 113 } 114 115 /** 116 * It should be less than {@link \dokuwiki\Parsing\ParserMode\Media::getSort()} 117 * (It was 320 at the time of writing this code) 118 * @return int 119 * 120 */ 121 function getSort() 122 { 123 return 319; 124 } 125 126 127 function connectTo($mode) 128 { 129 $enable = $this->getConf(self::CONF_IMAGE_ENABLE, 1); 130 if (!$enable) { 131 132 // Inside a card, we need to take over and enable it 133 $modes = [ 134 PluginUtility::getModeFromTag(syntax_plugin_combo_card::TAG), 135 ]; 136 $enable = in_array($mode, $modes); 137 } 138 139 if ($enable) { 140 if ($mode !== PluginUtility::getModeFromPluginName(ThirdPartyPlugins::IMAGE_MAPPING_NAME)) { 141 $this->Lexer->addSpecialPattern(self::MEDIA_PATTERN, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 142 } 143 } 144 } 145 146 147 function handle($match, $state, $pos, Doku_Handler $handler): array 148 { 149 150 switch ($state) { 151 152 153 // As this is a container, this cannot happens but yeah, now, you know 154 case DOKU_LEXER_SPECIAL : 155 156 $media = MediaLink::createFromRenderMatch($match); 157 $attributes = $media->toCallStackArray(); 158 159 $callStack = CallStack::createFromHandler($handler); 160 161 /** 162 * Parent 163 */ 164 $parent = $callStack->moveToParent(); 165 $parentTag = ""; 166 if (!empty($parent)) { 167 $parentTag = $parent->getTagName(); 168 if ($parentTag == syntax_plugin_combo_link::TAG) { 169 /** 170 * TODO: should be on the exit tag of the link 171 * The image is in a link, we don't want another link 172 * to the image 173 */ 174 $attributes[MediaLink::LINKING_KEY] = MediaLink::LINKING_NOLINK_VALUE; 175 } 176 } 177 178 return array( 179 PluginUtility::STATE => $state, 180 PluginUtility::ATTRIBUTES => $attributes, 181 PluginUtility::CONTEXT => $parentTag 182 ); 183 184 185 } 186 return array(); 187 188 } 189 190 /** 191 * Render the output 192 * @param string $format 193 * @param Doku_Renderer $renderer 194 * @param array $data - what the function handle() return'ed 195 * @return boolean - rendered correctly? (however, returned value is not used at the moment) 196 * @see DokuWiki_Syntax_Plugin::render() 197 * 198 * 199 */ 200 function render($format, Doku_Renderer $renderer, $data) 201 { 202 203 switch ($format) { 204 205 case 'xhtml': 206 207 /** @var Doku_Renderer_xhtml $renderer */ 208 $attributes = $data[PluginUtility::ATTRIBUTES]; 209 $mediaLink = MediaLink::createFromCallStackArray($attributes,$renderer->date_at); 210 $media = $mediaLink->getMedia(); 211 if ($media->getPath()->getScheme() == DokuFs::SCHEME) { 212 if ($media->getPath()->getMime()->isImage() || $media->getPath()->getExtension() === "svg") { 213 try { 214 $renderer->doc .= $mediaLink->renderMediaTagWithLink(); 215 } catch (RuntimeException $e) { 216 $errorClass = self::SVG_RENDERING_ERROR_CLASS; 217 $message = "Media ({$media->getPath()}). Error while rendering: {$e->getMessage()}"; 218 $renderer->doc .= "<span class=\"text-alert $errorClass\">" . hsc(trim($message)) . "</span>"; 219 LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, MediaLink::CANONICAL); 220 } 221 return true; 222 } 223 } 224 225 /** 226 * This is not an local internal media image (a video or an url image) 227 * Dokuwiki takes over 228 */ 229 $type = $attributes[MediaLink::MEDIA_DOKUWIKI_TYPE]; 230 $src = $attributes['src']; 231 $title = $attributes['title']; 232 $align = $attributes['align']; 233 $width = $attributes['width']; 234 $height = $attributes['height']; 235 $cache = $attributes['cache']; 236 if ($cache == null) { 237 // Dokuwiki needs a value 238 // If their is no value it will output it without any value 239 // in the query string. 240 $cache = "cache"; 241 } 242 $linking = $attributes['linking']; 243 switch ($type) { 244 case MediaLink::INTERNAL_MEDIA_CALL_NAME: 245 $renderer->doc .= $renderer->internalmedia($src, $title, $align, $width, $height, $cache, $linking, true); 246 break; 247 case MediaLink::EXTERNAL_MEDIA_CALL_NAME: 248 $renderer->doc .= $renderer->externalmedia($src, $title, $align, $width, $height, $cache, $linking, true); 249 break; 250 default: 251 LogUtility::msg("The dokuwiki media type ($type) is unknown"); 252 break; 253 } 254 255 return true; 256 257 case 258 "metadata": 259 260 /** 261 * Keep track of the metadata 262 * @var Doku_Renderer_metadata $renderer 263 */ 264 $attributes = $data[PluginUtility::ATTRIBUTES]; 265 self::registerImageMeta($attributes, $renderer); 266 return true; 267 268 case renderer_plugin_combo_analytics::RENDERER_FORMAT: 269 270 /** 271 * Special pattern call 272 * @var renderer_plugin_combo_analytics $renderer 273 */ 274 $attributes = $data[PluginUtility::ATTRIBUTES]; 275 self::updateStatistics($attributes, $renderer); 276 return true; 277 278 } 279 // unsupported $mode 280 return false; 281 } 282 283 /** 284 * Update the index for the move plugin 285 * and {@link Metadata::FIRST_IMAGE_META_RELATION} 286 * 287 * @param array $attributes 288 * @param Doku_Renderer_metadata $renderer 289 */ 290 static public function registerImageMeta($attributes, $renderer) 291 { 292 $type = $attributes[MediaLink::MEDIA_DOKUWIKI_TYPE]; 293 $src = $attributes['src']; 294 if ($src == null) { 295 $src = $attributes[PagePath::PROPERTY_NAME]; 296 } 297 $title = $attributes['title']; 298 $align = $attributes['align']; 299 $width = $attributes['width']; 300 $height = $attributes['height']; 301 $cache = $attributes['cache']; // Cache: https://www.dokuwiki.org/images#caching 302 $linking = $attributes['linking']; 303 304 switch ($type) { 305 case MediaLink::INTERNAL_MEDIA_CALL_NAME: 306 $renderer->internalmedia($src, $title, $align, $width, $height, $cache, $linking); 307 break; 308 case MediaLink::EXTERNAL_MEDIA_CALL_NAME: 309 $renderer->externalmedia($src, $title, $align, $width, $height, $cache, $linking); 310 break; 311 default: 312 LogUtility::msg("The dokuwiki media type ($type) for metadata registration is unknown"); 313 break; 314 } 315 316 } 317 318 319} 320 321