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