121913ab3SNickeau<?php 221913ab3SNickeau 321913ab3SNickeau 4e8b2ff59SNickeauuse ComboStrap\Analytics; 5*37748cd8SNickeauuse ComboStrap\CallStack; 623723136Sgerardnicouse ComboStrap\DokuPath; 723723136Sgerardnicouse ComboStrap\LogUtility; 823723136Sgerardnicouse ComboStrap\MediaLink; 921913ab3SNickeauuse ComboStrap\PluginUtility; 10*37748cd8SNickeauuse ComboStrap\ThirdPartyPlugins; 1121913ab3SNickeau 1221913ab3SNickeau 13*37748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 1421913ab3SNickeau 1521913ab3SNickeau 1621913ab3SNickeau/** 1723723136Sgerardnico * Media 1823723136Sgerardnico * 1923723136Sgerardnico * Takes over the {@link \dokuwiki\Parsing\ParserMode\Media media mode} 2023723136Sgerardnico * that is processed by {@link Doku_Handler_Parse_Media} 2123723136Sgerardnico * 2223723136Sgerardnico * 2323723136Sgerardnico * 2423723136Sgerardnico * It can be a internal / external media 25*37748cd8SNickeau * 26*37748cd8SNickeau * See: 27*37748cd8SNickeau * https://developers.google.com/search/docs/advanced/guidelines/google-images 2821913ab3SNickeau */ 2921913ab3SNickeauclass syntax_plugin_combo_media extends DokuWiki_Syntax_Plugin 3021913ab3SNickeau{ 3121913ab3SNickeau 3221913ab3SNickeau 3321913ab3SNickeau const TAG = "media"; 3421913ab3SNickeau 3521913ab3SNickeau /** 3621913ab3SNickeau * Used in the move plugin 3721913ab3SNickeau * !!! The two last word of the plugin class !!! 3821913ab3SNickeau */ 3921913ab3SNickeau const COMPONENT = 'combo_' . self::TAG; 4021913ab3SNickeau 4121913ab3SNickeau 4221913ab3SNickeau /** 4323723136Sgerardnico * Found at {@link \dokuwiki\Parsing\ParserMode\Media} 4421913ab3SNickeau */ 4523723136Sgerardnico const MEDIA_PATTERN = "\{\{(?:[^>\}]|(?:\}[^\}]))+\}\}"; 4621913ab3SNickeau 47531e725cSNickeau /** 48531e725cSNickeau * Enable or disable the image 49531e725cSNickeau */ 50531e725cSNickeau const CONF_IMAGE_ENABLE = "imageEnable"; 51531e725cSNickeau 52*37748cd8SNickeau /** 53*37748cd8SNickeau * Svg Rendering error 54*37748cd8SNickeau */ 55*37748cd8SNickeau const SVG_RENDERING_ERROR_CLASS = "combo-svg-rendering-error"; 56*37748cd8SNickeau 57*37748cd8SNickeau 58*37748cd8SNickeau /** 59*37748cd8SNickeau * @param $attributes 60*37748cd8SNickeau * @param renderer_plugin_combo_analytics $renderer 61*37748cd8SNickeau */ 62*37748cd8SNickeau public static function updateStatistics($attributes, renderer_plugin_combo_analytics $renderer) 63*37748cd8SNickeau { 64*37748cd8SNickeau $media = MediaLink::createFromCallStackArray($attributes); 65*37748cd8SNickeau $renderer->stats[Analytics::MEDIAS_COUNT]++; 66*37748cd8SNickeau $scheme = $media->getScheme(); 67*37748cd8SNickeau switch ($scheme) { 68*37748cd8SNickeau case DokuPath::LOCAL_SCHEME: 69*37748cd8SNickeau $renderer->stats[Analytics::INTERNAL_MEDIAS_COUNT]++; 70*37748cd8SNickeau if (!$media->exists()) { 71*37748cd8SNickeau $renderer->stats[Analytics::INTERNAL_BROKEN_MEDIAS_COUNT]++; 72*37748cd8SNickeau } 73*37748cd8SNickeau break; 74*37748cd8SNickeau case DokuPath::INTERNET_SCHEME: 75*37748cd8SNickeau $renderer->stats[Analytics::EXTERNAL_MEDIAS_COUNT]++; 76*37748cd8SNickeau break; 77*37748cd8SNickeau } 78*37748cd8SNickeau } 79*37748cd8SNickeau 8021913ab3SNickeau 8121913ab3SNickeau function getType() 8221913ab3SNickeau { 8321913ab3SNickeau return 'formatting'; 8421913ab3SNickeau } 8521913ab3SNickeau 8621913ab3SNickeau /** 8721913ab3SNickeau * How Dokuwiki will add P element 8821913ab3SNickeau * 8921913ab3SNickeau * * 'normal' - The plugin can be used inside paragraphs (inline) 9021913ab3SNickeau * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 9121913ab3SNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 9221913ab3SNickeau * 9321913ab3SNickeau * @see DokuWiki_Syntax_Plugin::getPType() 9421913ab3SNickeau */ 9521913ab3SNickeau function getPType() 9621913ab3SNickeau { 9723723136Sgerardnico /** 9823723136Sgerardnico * An image is not a block (it can be inside paragraph) 9923723136Sgerardnico */ 10021913ab3SNickeau return 'normal'; 10121913ab3SNickeau } 10221913ab3SNickeau 10321913ab3SNickeau function getAllowedTypes() 10421913ab3SNickeau { 10521913ab3SNickeau return array('substition', 'formatting', 'disabled'); 10621913ab3SNickeau } 10721913ab3SNickeau 10823723136Sgerardnico /** 10923723136Sgerardnico * It should be less than {@link \dokuwiki\Parsing\ParserMode\Media::getSort()} 11023723136Sgerardnico * (It was 320 at the time of writing this code) 11123723136Sgerardnico * @return int 11223723136Sgerardnico * 11323723136Sgerardnico */ 11421913ab3SNickeau function getSort() 11521913ab3SNickeau { 11623723136Sgerardnico return 319; 11721913ab3SNickeau } 11821913ab3SNickeau 11921913ab3SNickeau 12021913ab3SNickeau function connectTo($mode) 12121913ab3SNickeau { 122531e725cSNickeau $enable = $this->getConf(self::CONF_IMAGE_ENABLE, 1); 12321913ab3SNickeau if (!$enable) { 12421913ab3SNickeau 12521913ab3SNickeau // Inside a card, we need to take over and enable it 12621913ab3SNickeau $modes = [ 1279337a630SNickeau PluginUtility::getModeFromTag(syntax_plugin_combo_card::TAG), 12821913ab3SNickeau ]; 12921913ab3SNickeau $enable = in_array($mode, $modes); 13021913ab3SNickeau } 13121913ab3SNickeau 13221913ab3SNickeau if ($enable) { 133*37748cd8SNickeau if ($mode !== PluginUtility::getModeFromPluginName(ThirdPartyPlugins::IMAGE_MAPPING_NAME)) { 1349337a630SNickeau $this->Lexer->addSpecialPattern(self::MEDIA_PATTERN, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 13521913ab3SNickeau } 13621913ab3SNickeau } 137*37748cd8SNickeau } 13821913ab3SNickeau 13921913ab3SNickeau 14021913ab3SNickeau function handle($match, $state, $pos, Doku_Handler $handler) 14121913ab3SNickeau { 14221913ab3SNickeau 14321913ab3SNickeau switch ($state) { 14421913ab3SNickeau 14521913ab3SNickeau 14621913ab3SNickeau // As this is a container, this cannot happens but yeah, now, you know 14721913ab3SNickeau case DOKU_LEXER_SPECIAL : 148*37748cd8SNickeau 14923723136Sgerardnico $media = MediaLink::createFromRenderMatch($match); 15021913ab3SNickeau $attributes = $media->toCallStackArray(); 151*37748cd8SNickeau 152*37748cd8SNickeau $callStack = CallStack::createFromHandler($handler); 153*37748cd8SNickeau 154*37748cd8SNickeau /** 155*37748cd8SNickeau * Parent 156*37748cd8SNickeau */ 157*37748cd8SNickeau $parent = $callStack->moveToParent(); 15821913ab3SNickeau $parentTag = ""; 15921913ab3SNickeau if (!empty($parent)) { 160*37748cd8SNickeau $parentTag = $parent->getTagName(); 16121913ab3SNickeau if ($parentTag == syntax_plugin_combo_link::TAG) { 16221913ab3SNickeau /** 16321913ab3SNickeau * The image is in a link, we don't want another link 16421913ab3SNickeau * to the image 16521913ab3SNickeau */ 166a6bf47aaSNickeau $attributes[MediaLink::LINKING_KEY] = MediaLink::LINKING_NOLINK_VALUE; 16721913ab3SNickeau } 16821913ab3SNickeau } 169*37748cd8SNickeau 17021913ab3SNickeau return array( 17121913ab3SNickeau PluginUtility::STATE => $state, 17221913ab3SNickeau PluginUtility::ATTRIBUTES => $attributes, 173*37748cd8SNickeau PluginUtility::CONTEXT => $parentTag 17421913ab3SNickeau ); 17521913ab3SNickeau 17621913ab3SNickeau 17721913ab3SNickeau } 17821913ab3SNickeau return array(); 17921913ab3SNickeau 18021913ab3SNickeau } 18121913ab3SNickeau 18221913ab3SNickeau /** 18321913ab3SNickeau * Render the output 18421913ab3SNickeau * @param string $format 18521913ab3SNickeau * @param Doku_Renderer $renderer 18621913ab3SNickeau * @param array $data - what the function handle() return'ed 18721913ab3SNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 18821913ab3SNickeau * @see DokuWiki_Syntax_Plugin::render() 18921913ab3SNickeau * 19021913ab3SNickeau * 19121913ab3SNickeau */ 19221913ab3SNickeau function render($format, Doku_Renderer $renderer, $data) 19321913ab3SNickeau { 19421913ab3SNickeau 19521913ab3SNickeau switch ($format) { 19621913ab3SNickeau 19721913ab3SNickeau case 'xhtml': 19821913ab3SNickeau 19921913ab3SNickeau /** @var Doku_Renderer_xhtml $renderer */ 20021913ab3SNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 20123723136Sgerardnico $media = MediaLink::createFromCallStackArray($attributes); 20223723136Sgerardnico if ($media->getScheme() == DokuPath::LOCAL_SCHEME) { 20323723136Sgerardnico $media = MediaLink::createFromCallStackArray($attributes, $renderer->date_at); 204*37748cd8SNickeau if ($media->isImage() || $media->getExtension() === "svg") { 2059337a630SNickeau /** 2069337a630SNickeau * We don't support crop 2079337a630SNickeau */ 2089337a630SNickeau $crop = false; 2099337a630SNickeau if ($media->getRequestedWidth() != null && $media->getRequestedHeight() != null) { 2109337a630SNickeau /** 2119337a630SNickeau * Width of 0 = resizing by height (supported) 2129337a630SNickeau */ 2139337a630SNickeau if ($media->getRequestedWidth() != "0") { 2149337a630SNickeau $crop = true; 2159337a630SNickeau } 2169337a630SNickeau } 2179337a630SNickeau if (!$crop) { 218*37748cd8SNickeau try { 21921913ab3SNickeau $renderer->doc .= $media->renderMediaTagWithLink(); 220*37748cd8SNickeau } catch (RuntimeException $e) { 221*37748cd8SNickeau $errorClass = self::SVG_RENDERING_ERROR_CLASS; 222*37748cd8SNickeau $message = "Media ({$media->getPath()}). Error while rendering: {$e->getMessage()}"; 223*37748cd8SNickeau $renderer->doc .= "<span class=\"text-alert $errorClass\">" . hsc($message) . "</span>"; 224*37748cd8SNickeau if(!PluginUtility::isTest()) { 225*37748cd8SNickeau LogUtility::msg($message, LogUtility::LVL_MSG_WARNING, MediaLink::CANONICAL); 226*37748cd8SNickeau } 227*37748cd8SNickeau } 22823723136Sgerardnico return true; 22923723136Sgerardnico } 23023723136Sgerardnico } 2319337a630SNickeau } 23221913ab3SNickeau 23321913ab3SNickeau /** 23423723136Sgerardnico * This is not an local internal media image (a video or an url image) 23521913ab3SNickeau * Dokuwiki takes over 23621913ab3SNickeau */ 237531e725cSNickeau $type = $attributes[MediaLink::MEDIA_DOKUWIKI_TYPE]; 23821913ab3SNickeau $src = $attributes['src']; 23921913ab3SNickeau $title = $attributes['title']; 24021913ab3SNickeau $align = $attributes['align']; 24121913ab3SNickeau $width = $attributes['width']; 24221913ab3SNickeau $height = $attributes['height']; 24321913ab3SNickeau $cache = $attributes['cache']; 244a6bf47aaSNickeau if ($cache == null) { 245a6bf47aaSNickeau // Dokuwiki needs a value 246a6bf47aaSNickeau // If their is no value it will output it without any value 247a6bf47aaSNickeau // in the query string. 248a6bf47aaSNickeau $cache = "cache"; 249a6bf47aaSNickeau } 25021913ab3SNickeau $linking = $attributes['linking']; 25123723136Sgerardnico switch ($type) { 252531e725cSNickeau case MediaLink::INTERNAL_MEDIA_CALL_NAME: 25321913ab3SNickeau $renderer->doc .= $renderer->internalmedia($src, $title, $align, $width, $height, $cache, $linking, true); 25423723136Sgerardnico break; 255531e725cSNickeau case MediaLink::EXTERNAL_MEDIA_CALL_NAME: 25623723136Sgerardnico $renderer->doc .= $renderer->externalmedia($src, $title, $align, $width, $height, $cache, $linking, true); 25723723136Sgerardnico break; 25823723136Sgerardnico default: 25923723136Sgerardnico LogUtility::msg("The dokuwiki media type ($type) is unknown"); 26023723136Sgerardnico break; 26121913ab3SNickeau } 26221913ab3SNickeau 26323723136Sgerardnico return true; 26421913ab3SNickeau 2659337a630SNickeau case 2669337a630SNickeau "metadata": 26721913ab3SNickeau 26821913ab3SNickeau /** 26921913ab3SNickeau * Keep track of the metadata 27021913ab3SNickeau * @var Doku_Renderer_metadata $renderer 27121913ab3SNickeau */ 272*37748cd8SNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 27321913ab3SNickeau self::registerImageMeta($attributes, $renderer); 27423723136Sgerardnico return true; 27521913ab3SNickeau 276e8b2ff59SNickeau case renderer_plugin_combo_analytics::RENDERER_FORMAT: 277e8b2ff59SNickeau 278e8b2ff59SNickeau /** 279e8b2ff59SNickeau * Special pattern call 280e8b2ff59SNickeau * @var renderer_plugin_combo_analytics $renderer 281e8b2ff59SNickeau */ 282e8b2ff59SNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 283*37748cd8SNickeau self::updateStatistics($attributes, $renderer); 284e8b2ff59SNickeau return true; 285e8b2ff59SNickeau 28621913ab3SNickeau } 28721913ab3SNickeau // unsupported $mode 28821913ab3SNickeau return false; 28921913ab3SNickeau } 29021913ab3SNickeau 29121913ab3SNickeau /** 292*37748cd8SNickeau * Update the index for the move plugin 293*37748cd8SNickeau * and {@link Page::FIRST_IMAGE_META_RELATION} 294*37748cd8SNickeau * 29521913ab3SNickeau * @param array $attributes 29621913ab3SNickeau * @param Doku_Renderer_metadata $renderer 29721913ab3SNickeau */ 29821913ab3SNickeau static public function registerImageMeta($attributes, $renderer) 29921913ab3SNickeau { 300531e725cSNickeau $type = $attributes[MediaLink::MEDIA_DOKUWIKI_TYPE]; 30121913ab3SNickeau $src = $attributes['src']; 302531e725cSNickeau if ($src == null) { 303531e725cSNickeau $src = $attributes[DokuPath::PATH_ATTRIBUTE]; 304531e725cSNickeau } 30521913ab3SNickeau $title = $attributes['title']; 30621913ab3SNickeau $align = $attributes['align']; 30721913ab3SNickeau $width = $attributes['width']; 30821913ab3SNickeau $height = $attributes['height']; 30921913ab3SNickeau $cache = $attributes['cache']; // Cache: https://www.dokuwiki.org/images#caching 31021913ab3SNickeau $linking = $attributes['linking']; 31123723136Sgerardnico 31223723136Sgerardnico switch ($type) { 313531e725cSNickeau case MediaLink::INTERNAL_MEDIA_CALL_NAME: 31421913ab3SNickeau $renderer->internalmedia($src, $title, $align, $width, $height, $cache, $linking); 31523723136Sgerardnico break; 316531e725cSNickeau case MediaLink::EXTERNAL_MEDIA_CALL_NAME: 31723723136Sgerardnico $renderer->externalmedia($src, $title, $align, $width, $height, $cache, $linking); 31823723136Sgerardnico break; 31923723136Sgerardnico default: 32023723136Sgerardnico LogUtility::msg("The dokuwiki media type ($type) for metadata registration is unknown"); 32123723136Sgerardnico break; 32223723136Sgerardnico } 32323723136Sgerardnico 32421913ab3SNickeau } 32521913ab3SNickeau 32621913ab3SNickeau 32721913ab3SNickeau} 32821913ab3SNickeau 329