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