xref: /plugin/combo/syntax/media.php (revision c3437056399326d621a01da73b649707fbb0ae69)
121913ab3SNickeau<?php
221913ab3SNickeau
321913ab3SNickeau
4*c3437056SNickeauuse ComboStrap\AnalyticsDocument;
537748cd8SNickeauuse ComboStrap\CallStack;
6*c3437056SNickeauuse ComboStrap\DokuFs;
723723136Sgerardnicouse ComboStrap\DokuPath;
81fa8c418SNickeauuse ComboStrap\Image;
9*c3437056SNickeauuse ComboStrap\InternetPath;
1023723136Sgerardnicouse ComboStrap\LogUtility;
1123723136Sgerardnicouse ComboStrap\MediaLink;
12*c3437056SNickeauuse ComboStrap\Metadata;
13*c3437056SNickeauuse ComboStrap\PagePath;
14*c3437056SNickeauuse ComboStrap\Path;
1521913ab3SNickeauuse ComboStrap\PluginUtility;
1637748cd8SNickeauuse ComboStrap\ThirdPartyPlugins;
1721913ab3SNickeau
1821913ab3SNickeau
1937748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
2021913ab3SNickeau
2121913ab3SNickeau
2221913ab3SNickeau/**
2323723136Sgerardnico * Media
2423723136Sgerardnico *
2523723136Sgerardnico * Takes over the {@link \dokuwiki\Parsing\ParserMode\Media media mode}
2623723136Sgerardnico * that is processed by {@link Doku_Handler_Parse_Media}
2723723136Sgerardnico *
2823723136Sgerardnico *
2923723136Sgerardnico *
3023723136Sgerardnico * It can be a internal / external media
3137748cd8SNickeau *
321fa8c418SNickeau *
3337748cd8SNickeau * See:
3437748cd8SNickeau * https://developers.google.com/search/docs/advanced/guidelines/google-images
3521913ab3SNickeau */
3621913ab3SNickeauclass syntax_plugin_combo_media extends DokuWiki_Syntax_Plugin
3721913ab3SNickeau{
3821913ab3SNickeau
3921913ab3SNickeau
4021913ab3SNickeau    const TAG = "media";
4121913ab3SNickeau
4221913ab3SNickeau    /**
4321913ab3SNickeau     * Used in the move plugin
4421913ab3SNickeau     * !!! The two last word of the plugin class !!!
4521913ab3SNickeau     */
4621913ab3SNickeau    const COMPONENT = 'combo_' . self::TAG;
4721913ab3SNickeau
4821913ab3SNickeau
4921913ab3SNickeau    /**
5023723136Sgerardnico     * Found at {@link \dokuwiki\Parsing\ParserMode\Media}
5121913ab3SNickeau     */
5223723136Sgerardnico    const MEDIA_PATTERN = "\{\{(?:[^>\}]|(?:\}[^\}]))+\}\}";
5321913ab3SNickeau
54531e725cSNickeau    /**
55531e725cSNickeau     * Enable or disable the image
56531e725cSNickeau     */
57531e725cSNickeau    const CONF_IMAGE_ENABLE = "imageEnable";
58531e725cSNickeau
5937748cd8SNickeau    /**
6037748cd8SNickeau     * Svg Rendering error
6137748cd8SNickeau     */
6237748cd8SNickeau    const SVG_RENDERING_ERROR_CLASS = "combo-svg-rendering-error";
6337748cd8SNickeau
6437748cd8SNickeau
6537748cd8SNickeau    /**
6637748cd8SNickeau     * @param $attributes
6737748cd8SNickeau     * @param renderer_plugin_combo_analytics $renderer
6837748cd8SNickeau     */
6937748cd8SNickeau    public static function updateStatistics($attributes, renderer_plugin_combo_analytics $renderer)
7037748cd8SNickeau    {
7137748cd8SNickeau        $media = MediaLink::createFromCallStackArray($attributes);
72*c3437056SNickeau        $renderer->stats[AnalyticsDocument::MEDIA_COUNT]++;
73*c3437056SNickeau        $scheme = $media->getMedia()->getPath()->getScheme();
7437748cd8SNickeau        switch ($scheme) {
75*c3437056SNickeau            case DokuFs::SCHEME:
76*c3437056SNickeau                $renderer->stats[AnalyticsDocument::INTERNAL_MEDIA_COUNT]++;
77*c3437056SNickeau                if (!$media->getMedia()->exists()) {
78*c3437056SNickeau                    $renderer->stats[AnalyticsDocument::INTERNAL_BROKEN_MEDIA_COUNT]++;
7937748cd8SNickeau                }
8037748cd8SNickeau                break;
81*c3437056SNickeau            case InternetPath::scheme:
82*c3437056SNickeau                $renderer->stats[AnalyticsDocument::EXTERNAL_MEDIA_COUNT]++;
8337748cd8SNickeau                break;
8437748cd8SNickeau        }
8537748cd8SNickeau    }
8637748cd8SNickeau
8721913ab3SNickeau
8821913ab3SNickeau    function getType()
8921913ab3SNickeau    {
9021913ab3SNickeau        return 'formatting';
9121913ab3SNickeau    }
9221913ab3SNickeau
9321913ab3SNickeau    /**
9421913ab3SNickeau     * How Dokuwiki will add P element
9521913ab3SNickeau     *
9621913ab3SNickeau     *  * 'normal' - The plugin can be used inside paragraphs (inline)
9721913ab3SNickeau     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
9821913ab3SNickeau     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
9921913ab3SNickeau     *
10021913ab3SNickeau     * @see DokuWiki_Syntax_Plugin::getPType()
10121913ab3SNickeau     */
10221913ab3SNickeau    function getPType()
10321913ab3SNickeau    {
10423723136Sgerardnico        /**
10523723136Sgerardnico         * An image is not a block (it can be inside paragraph)
10623723136Sgerardnico         */
10721913ab3SNickeau        return 'normal';
10821913ab3SNickeau    }
10921913ab3SNickeau
11021913ab3SNickeau    function getAllowedTypes()
11121913ab3SNickeau    {
11221913ab3SNickeau        return array('substition', 'formatting', 'disabled');
11321913ab3SNickeau    }
11421913ab3SNickeau
11523723136Sgerardnico    /**
11623723136Sgerardnico     * It should be less than {@link \dokuwiki\Parsing\ParserMode\Media::getSort()}
11723723136Sgerardnico     * (It was 320 at the time of writing this code)
11823723136Sgerardnico     * @return int
11923723136Sgerardnico     *
12023723136Sgerardnico     */
12121913ab3SNickeau    function getSort()
12221913ab3SNickeau    {
12323723136Sgerardnico        return 319;
12421913ab3SNickeau    }
12521913ab3SNickeau
12621913ab3SNickeau
12721913ab3SNickeau    function connectTo($mode)
12821913ab3SNickeau    {
129531e725cSNickeau        $enable = $this->getConf(self::CONF_IMAGE_ENABLE, 1);
13021913ab3SNickeau        if (!$enable) {
13121913ab3SNickeau
13221913ab3SNickeau            // Inside a card, we need to take over and enable it
13321913ab3SNickeau            $modes = [
1349337a630SNickeau                PluginUtility::getModeFromTag(syntax_plugin_combo_card::TAG),
13521913ab3SNickeau            ];
13621913ab3SNickeau            $enable = in_array($mode, $modes);
13721913ab3SNickeau        }
13821913ab3SNickeau
13921913ab3SNickeau        if ($enable) {
14037748cd8SNickeau            if ($mode !== PluginUtility::getModeFromPluginName(ThirdPartyPlugins::IMAGE_MAPPING_NAME)) {
1419337a630SNickeau                $this->Lexer->addSpecialPattern(self::MEDIA_PATTERN, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
14221913ab3SNickeau            }
14321913ab3SNickeau        }
14437748cd8SNickeau    }
14521913ab3SNickeau
14621913ab3SNickeau
1471fa8c418SNickeau    function handle($match, $state, $pos, Doku_Handler $handler): array
14821913ab3SNickeau    {
14921913ab3SNickeau
15021913ab3SNickeau        switch ($state) {
15121913ab3SNickeau
15221913ab3SNickeau
15321913ab3SNickeau            // As this is a container, this cannot happens but yeah, now, you know
15421913ab3SNickeau            case DOKU_LEXER_SPECIAL :
15537748cd8SNickeau
15623723136Sgerardnico                $media = MediaLink::createFromRenderMatch($match);
15721913ab3SNickeau                $attributes = $media->toCallStackArray();
15837748cd8SNickeau
15937748cd8SNickeau                $callStack = CallStack::createFromHandler($handler);
16037748cd8SNickeau
16137748cd8SNickeau                /**
16237748cd8SNickeau                 * Parent
16337748cd8SNickeau                 */
16437748cd8SNickeau                $parent = $callStack->moveToParent();
16521913ab3SNickeau                $parentTag = "";
16621913ab3SNickeau                if (!empty($parent)) {
16737748cd8SNickeau                    $parentTag = $parent->getTagName();
16821913ab3SNickeau                    if ($parentTag == syntax_plugin_combo_link::TAG) {
16921913ab3SNickeau                        /**
1701fa8c418SNickeau                         * TODO: should be on the exit tag of the link
17121913ab3SNickeau                         * The image is in a link, we don't want another link
17221913ab3SNickeau                         * to the image
17321913ab3SNickeau                         */
174a6bf47aaSNickeau                        $attributes[MediaLink::LINKING_KEY] = MediaLink::LINKING_NOLINK_VALUE;
17521913ab3SNickeau                    }
17621913ab3SNickeau                }
17737748cd8SNickeau
17821913ab3SNickeau                return array(
17921913ab3SNickeau                    PluginUtility::STATE => $state,
18021913ab3SNickeau                    PluginUtility::ATTRIBUTES => $attributes,
18137748cd8SNickeau                    PluginUtility::CONTEXT => $parentTag
18221913ab3SNickeau                );
18321913ab3SNickeau
18421913ab3SNickeau
18521913ab3SNickeau        }
18621913ab3SNickeau        return array();
18721913ab3SNickeau
18821913ab3SNickeau    }
18921913ab3SNickeau
19021913ab3SNickeau    /**
19121913ab3SNickeau     * Render the output
19221913ab3SNickeau     * @param string $format
19321913ab3SNickeau     * @param Doku_Renderer $renderer
19421913ab3SNickeau     * @param array $data - what the function handle() return'ed
19521913ab3SNickeau     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
19621913ab3SNickeau     * @see DokuWiki_Syntax_Plugin::render()
19721913ab3SNickeau     *
19821913ab3SNickeau     *
19921913ab3SNickeau     */
20021913ab3SNickeau    function render($format, Doku_Renderer $renderer, $data)
20121913ab3SNickeau    {
20221913ab3SNickeau
20321913ab3SNickeau        switch ($format) {
20421913ab3SNickeau
20521913ab3SNickeau            case 'xhtml':
20621913ab3SNickeau
20721913ab3SNickeau                /** @var Doku_Renderer_xhtml $renderer */
20821913ab3SNickeau                $attributes = $data[PluginUtility::ATTRIBUTES];
2091fa8c418SNickeau                $mediaLink = MediaLink::createFromCallStackArray($attributes,$renderer->date_at);
210*c3437056SNickeau                $media = $mediaLink->getMedia();
211*c3437056SNickeau                if ($media->getPath()->getScheme() == DokuFs::SCHEME) {
212*c3437056SNickeau                    if ($media->getPath()->getMime()->isImage() || $media->getPath()->getExtension() === "svg") {
21337748cd8SNickeau                        try {
2141fa8c418SNickeau                            $renderer->doc .= $mediaLink->renderMediaTagWithLink();
21537748cd8SNickeau                        } catch (RuntimeException $e) {
21637748cd8SNickeau                            $errorClass = self::SVG_RENDERING_ERROR_CLASS;
21737748cd8SNickeau                            $message = "Media ({$media->getPath()}). Error while rendering: {$e->getMessage()}";
2181fa8c418SNickeau                            $renderer->doc .= "<span class=\"text-alert $errorClass\">" . hsc(trim($message)) . "</span>";
2191fa8c418SNickeau                            LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, MediaLink::CANONICAL);
22037748cd8SNickeau                        }
22123723136Sgerardnico                        return true;
22223723136Sgerardnico                    }
22323723136Sgerardnico                }
22421913ab3SNickeau
22521913ab3SNickeau                /**
22623723136Sgerardnico                 * This is not an local internal media image (a video or an url image)
22721913ab3SNickeau                 * Dokuwiki takes over
22821913ab3SNickeau                 */
229531e725cSNickeau                $type = $attributes[MediaLink::MEDIA_DOKUWIKI_TYPE];
23021913ab3SNickeau                $src = $attributes['src'];
23121913ab3SNickeau                $title = $attributes['title'];
23221913ab3SNickeau                $align = $attributes['align'];
23321913ab3SNickeau                $width = $attributes['width'];
23421913ab3SNickeau                $height = $attributes['height'];
23521913ab3SNickeau                $cache = $attributes['cache'];
236a6bf47aaSNickeau                if ($cache == null) {
237a6bf47aaSNickeau                    // Dokuwiki needs a value
238a6bf47aaSNickeau                    // If their is no value it will output it without any value
239a6bf47aaSNickeau                    // in the query string.
240a6bf47aaSNickeau                    $cache = "cache";
241a6bf47aaSNickeau                }
24221913ab3SNickeau                $linking = $attributes['linking'];
24323723136Sgerardnico                switch ($type) {
244531e725cSNickeau                    case MediaLink::INTERNAL_MEDIA_CALL_NAME:
24521913ab3SNickeau                        $renderer->doc .= $renderer->internalmedia($src, $title, $align, $width, $height, $cache, $linking, true);
24623723136Sgerardnico                        break;
247531e725cSNickeau                    case MediaLink::EXTERNAL_MEDIA_CALL_NAME:
24823723136Sgerardnico                        $renderer->doc .= $renderer->externalmedia($src, $title, $align, $width, $height, $cache, $linking, true);
24923723136Sgerardnico                        break;
25023723136Sgerardnico                    default:
25123723136Sgerardnico                        LogUtility::msg("The dokuwiki media type ($type) is unknown");
25223723136Sgerardnico                        break;
25321913ab3SNickeau                }
25421913ab3SNickeau
25523723136Sgerardnico                return true;
25621913ab3SNickeau
2579337a630SNickeau            case
2589337a630SNickeau            "metadata":
25921913ab3SNickeau
26021913ab3SNickeau                /**
26121913ab3SNickeau                 * Keep track of the metadata
26221913ab3SNickeau                 * @var Doku_Renderer_metadata $renderer
26321913ab3SNickeau                 */
26437748cd8SNickeau                $attributes = $data[PluginUtility::ATTRIBUTES];
26521913ab3SNickeau                self::registerImageMeta($attributes, $renderer);
26623723136Sgerardnico                return true;
26721913ab3SNickeau
268e8b2ff59SNickeau            case renderer_plugin_combo_analytics::RENDERER_FORMAT:
269e8b2ff59SNickeau
270e8b2ff59SNickeau                /**
271e8b2ff59SNickeau                 * Special pattern call
272e8b2ff59SNickeau                 * @var renderer_plugin_combo_analytics $renderer
273e8b2ff59SNickeau                 */
274e8b2ff59SNickeau                $attributes = $data[PluginUtility::ATTRIBUTES];
27537748cd8SNickeau                self::updateStatistics($attributes, $renderer);
276e8b2ff59SNickeau                return true;
277e8b2ff59SNickeau
27821913ab3SNickeau        }
27921913ab3SNickeau        // unsupported $mode
28021913ab3SNickeau        return false;
28121913ab3SNickeau    }
28221913ab3SNickeau
28321913ab3SNickeau    /**
28437748cd8SNickeau     * Update the index for the move plugin
285*c3437056SNickeau     * and {@link Metadata::FIRST_IMAGE_META_RELATION}
28637748cd8SNickeau     *
28721913ab3SNickeau     * @param array $attributes
28821913ab3SNickeau     * @param Doku_Renderer_metadata $renderer
28921913ab3SNickeau     */
29021913ab3SNickeau    static public function registerImageMeta($attributes, $renderer)
29121913ab3SNickeau    {
292531e725cSNickeau        $type = $attributes[MediaLink::MEDIA_DOKUWIKI_TYPE];
29321913ab3SNickeau        $src = $attributes['src'];
294531e725cSNickeau        if ($src == null) {
295*c3437056SNickeau            $src = $attributes[PagePath::PROPERTY_NAME];
296531e725cSNickeau        }
29721913ab3SNickeau        $title = $attributes['title'];
29821913ab3SNickeau        $align = $attributes['align'];
29921913ab3SNickeau        $width = $attributes['width'];
30021913ab3SNickeau        $height = $attributes['height'];
30121913ab3SNickeau        $cache = $attributes['cache']; // Cache: https://www.dokuwiki.org/images#caching
30221913ab3SNickeau        $linking = $attributes['linking'];
30323723136Sgerardnico
30423723136Sgerardnico        switch ($type) {
305531e725cSNickeau            case MediaLink::INTERNAL_MEDIA_CALL_NAME:
30621913ab3SNickeau                $renderer->internalmedia($src, $title, $align, $width, $height, $cache, $linking);
30723723136Sgerardnico                break;
308531e725cSNickeau            case MediaLink::EXTERNAL_MEDIA_CALL_NAME:
30923723136Sgerardnico                $renderer->externalmedia($src, $title, $align, $width, $height, $cache, $linking);
31023723136Sgerardnico                break;
31123723136Sgerardnico            default:
31223723136Sgerardnico                LogUtility::msg("The dokuwiki media type ($type)  for metadata registration is unknown");
31323723136Sgerardnico                break;
31423723136Sgerardnico        }
31523723136Sgerardnico
31621913ab3SNickeau    }
31721913ab3SNickeau
31821913ab3SNickeau
31921913ab3SNickeau}
32021913ab3SNickeau
321