xref: /plugin/combo/syntax/media.php (revision 1fa8c418ed5809db58049141be41b7738471dd32)
121913ab3SNickeau<?php
221913ab3SNickeau
321913ab3SNickeau
4e8b2ff59SNickeauuse ComboStrap\Analytics;
537748cd8SNickeauuse ComboStrap\CallStack;
623723136Sgerardnicouse ComboStrap\DokuPath;
7*1fa8c418SNickeauuse ComboStrap\Image;
823723136Sgerardnicouse ComboStrap\LogUtility;
923723136Sgerardnicouse ComboStrap\MediaLink;
1021913ab3SNickeauuse ComboStrap\PluginUtility;
1137748cd8SNickeauuse ComboStrap\ThirdPartyPlugins;
1221913ab3SNickeau
1321913ab3SNickeau
1437748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
1521913ab3SNickeau
1621913ab3SNickeau
1721913ab3SNickeau/**
1823723136Sgerardnico * Media
1923723136Sgerardnico *
2023723136Sgerardnico * Takes over the {@link \dokuwiki\Parsing\ParserMode\Media media mode}
2123723136Sgerardnico * that is processed by {@link Doku_Handler_Parse_Media}
2223723136Sgerardnico *
2323723136Sgerardnico *
2423723136Sgerardnico *
2523723136Sgerardnico * It can be a internal / external media
2637748cd8SNickeau *
27*1fa8c418SNickeau *
2837748cd8SNickeau * See:
2937748cd8SNickeau * https://developers.google.com/search/docs/advanced/guidelines/google-images
3021913ab3SNickeau */
3121913ab3SNickeauclass syntax_plugin_combo_media extends DokuWiki_Syntax_Plugin
3221913ab3SNickeau{
3321913ab3SNickeau
3421913ab3SNickeau
3521913ab3SNickeau    const TAG = "media";
3621913ab3SNickeau
3721913ab3SNickeau    /**
3821913ab3SNickeau     * Used in the move plugin
3921913ab3SNickeau     * !!! The two last word of the plugin class !!!
4021913ab3SNickeau     */
4121913ab3SNickeau    const COMPONENT = 'combo_' . self::TAG;
4221913ab3SNickeau
4321913ab3SNickeau
4421913ab3SNickeau    /**
4523723136Sgerardnico     * Found at {@link \dokuwiki\Parsing\ParserMode\Media}
4621913ab3SNickeau     */
4723723136Sgerardnico    const MEDIA_PATTERN = "\{\{(?:[^>\}]|(?:\}[^\}]))+\}\}";
4821913ab3SNickeau
49531e725cSNickeau    /**
50531e725cSNickeau     * Enable or disable the image
51531e725cSNickeau     */
52531e725cSNickeau    const CONF_IMAGE_ENABLE = "imageEnable";
53531e725cSNickeau
5437748cd8SNickeau    /**
5537748cd8SNickeau     * Svg Rendering error
5637748cd8SNickeau     */
5737748cd8SNickeau    const SVG_RENDERING_ERROR_CLASS = "combo-svg-rendering-error";
5837748cd8SNickeau
5937748cd8SNickeau
6037748cd8SNickeau    /**
6137748cd8SNickeau     * @param $attributes
6237748cd8SNickeau     * @param renderer_plugin_combo_analytics $renderer
6337748cd8SNickeau     */
6437748cd8SNickeau    public static function updateStatistics($attributes, renderer_plugin_combo_analytics $renderer)
6537748cd8SNickeau    {
6637748cd8SNickeau        $media = MediaLink::createFromCallStackArray($attributes);
67*1fa8c418SNickeau        $renderer->stats[Analytics::MEDIA_COUNT]++;
68*1fa8c418SNickeau        $scheme = $media->getDefaultImage()->getScheme();
6937748cd8SNickeau        switch ($scheme) {
7037748cd8SNickeau            case DokuPath::LOCAL_SCHEME:
71*1fa8c418SNickeau                $renderer->stats[Analytics::INTERNAL_MEDIA_COUNT]++;
72*1fa8c418SNickeau                if (!$media->getDefaultImage()->exists()) {
73*1fa8c418SNickeau                    $renderer->stats[Analytics::INTERNAL_BROKEN_MEDIA_COUNT]++;
7437748cd8SNickeau                }
7537748cd8SNickeau                break;
7637748cd8SNickeau            case DokuPath::INTERNET_SCHEME:
77*1fa8c418SNickeau                $renderer->stats[Analytics::EXTERNAL_MEDIA_COUNT]++;
7837748cd8SNickeau                break;
7937748cd8SNickeau        }
8037748cd8SNickeau    }
8137748cd8SNickeau
8221913ab3SNickeau
8321913ab3SNickeau    function getType()
8421913ab3SNickeau    {
8521913ab3SNickeau        return 'formatting';
8621913ab3SNickeau    }
8721913ab3SNickeau
8821913ab3SNickeau    /**
8921913ab3SNickeau     * How Dokuwiki will add P element
9021913ab3SNickeau     *
9121913ab3SNickeau     *  * 'normal' - The plugin can be used inside paragraphs (inline)
9221913ab3SNickeau     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
9321913ab3SNickeau     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
9421913ab3SNickeau     *
9521913ab3SNickeau     * @see DokuWiki_Syntax_Plugin::getPType()
9621913ab3SNickeau     */
9721913ab3SNickeau    function getPType()
9821913ab3SNickeau    {
9923723136Sgerardnico        /**
10023723136Sgerardnico         * An image is not a block (it can be inside paragraph)
10123723136Sgerardnico         */
10221913ab3SNickeau        return 'normal';
10321913ab3SNickeau    }
10421913ab3SNickeau
10521913ab3SNickeau    function getAllowedTypes()
10621913ab3SNickeau    {
10721913ab3SNickeau        return array('substition', 'formatting', 'disabled');
10821913ab3SNickeau    }
10921913ab3SNickeau
11023723136Sgerardnico    /**
11123723136Sgerardnico     * It should be less than {@link \dokuwiki\Parsing\ParserMode\Media::getSort()}
11223723136Sgerardnico     * (It was 320 at the time of writing this code)
11323723136Sgerardnico     * @return int
11423723136Sgerardnico     *
11523723136Sgerardnico     */
11621913ab3SNickeau    function getSort()
11721913ab3SNickeau    {
11823723136Sgerardnico        return 319;
11921913ab3SNickeau    }
12021913ab3SNickeau
12121913ab3SNickeau
12221913ab3SNickeau    function connectTo($mode)
12321913ab3SNickeau    {
124531e725cSNickeau        $enable = $this->getConf(self::CONF_IMAGE_ENABLE, 1);
12521913ab3SNickeau        if (!$enable) {
12621913ab3SNickeau
12721913ab3SNickeau            // Inside a card, we need to take over and enable it
12821913ab3SNickeau            $modes = [
1299337a630SNickeau                PluginUtility::getModeFromTag(syntax_plugin_combo_card::TAG),
13021913ab3SNickeau            ];
13121913ab3SNickeau            $enable = in_array($mode, $modes);
13221913ab3SNickeau        }
13321913ab3SNickeau
13421913ab3SNickeau        if ($enable) {
13537748cd8SNickeau            if ($mode !== PluginUtility::getModeFromPluginName(ThirdPartyPlugins::IMAGE_MAPPING_NAME)) {
1369337a630SNickeau                $this->Lexer->addSpecialPattern(self::MEDIA_PATTERN, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
13721913ab3SNickeau            }
13821913ab3SNickeau        }
13937748cd8SNickeau    }
14021913ab3SNickeau
14121913ab3SNickeau
142*1fa8c418SNickeau    function handle($match, $state, $pos, Doku_Handler $handler): array
14321913ab3SNickeau    {
14421913ab3SNickeau
14521913ab3SNickeau        switch ($state) {
14621913ab3SNickeau
14721913ab3SNickeau
14821913ab3SNickeau            // As this is a container, this cannot happens but yeah, now, you know
14921913ab3SNickeau            case DOKU_LEXER_SPECIAL :
15037748cd8SNickeau
15123723136Sgerardnico                $media = MediaLink::createFromRenderMatch($match);
15221913ab3SNickeau                $attributes = $media->toCallStackArray();
15337748cd8SNickeau
15437748cd8SNickeau                $callStack = CallStack::createFromHandler($handler);
15537748cd8SNickeau
15637748cd8SNickeau                /**
15737748cd8SNickeau                 * Parent
15837748cd8SNickeau                 */
15937748cd8SNickeau                $parent = $callStack->moveToParent();
16021913ab3SNickeau                $parentTag = "";
16121913ab3SNickeau                if (!empty($parent)) {
16237748cd8SNickeau                    $parentTag = $parent->getTagName();
16321913ab3SNickeau                    if ($parentTag == syntax_plugin_combo_link::TAG) {
16421913ab3SNickeau                        /**
165*1fa8c418SNickeau                         * TODO: should be on the exit tag of the link
16621913ab3SNickeau                         * The image is in a link, we don't want another link
16721913ab3SNickeau                         * to the image
16821913ab3SNickeau                         */
169a6bf47aaSNickeau                        $attributes[MediaLink::LINKING_KEY] = MediaLink::LINKING_NOLINK_VALUE;
17021913ab3SNickeau                    }
17121913ab3SNickeau                }
17237748cd8SNickeau
17321913ab3SNickeau                return array(
17421913ab3SNickeau                    PluginUtility::STATE => $state,
17521913ab3SNickeau                    PluginUtility::ATTRIBUTES => $attributes,
17637748cd8SNickeau                    PluginUtility::CONTEXT => $parentTag
17721913ab3SNickeau                );
17821913ab3SNickeau
17921913ab3SNickeau
18021913ab3SNickeau        }
18121913ab3SNickeau        return array();
18221913ab3SNickeau
18321913ab3SNickeau    }
18421913ab3SNickeau
18521913ab3SNickeau    /**
18621913ab3SNickeau     * Render the output
18721913ab3SNickeau     * @param string $format
18821913ab3SNickeau     * @param Doku_Renderer $renderer
18921913ab3SNickeau     * @param array $data - what the function handle() return'ed
19021913ab3SNickeau     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
19121913ab3SNickeau     * @see DokuWiki_Syntax_Plugin::render()
19221913ab3SNickeau     *
19321913ab3SNickeau     *
19421913ab3SNickeau     */
19521913ab3SNickeau    function render($format, Doku_Renderer $renderer, $data)
19621913ab3SNickeau    {
19721913ab3SNickeau
19821913ab3SNickeau        switch ($format) {
19921913ab3SNickeau
20021913ab3SNickeau            case 'xhtml':
20121913ab3SNickeau
20221913ab3SNickeau                /** @var Doku_Renderer_xhtml $renderer */
20321913ab3SNickeau                $attributes = $data[PluginUtility::ATTRIBUTES];
204*1fa8c418SNickeau                $mediaLink = MediaLink::createFromCallStackArray($attributes);
205*1fa8c418SNickeau                $media = $mediaLink->getMedia();
20623723136Sgerardnico                if ($media->getScheme() == DokuPath::LOCAL_SCHEME) {
207*1fa8c418SNickeau                    $mediaLink = MediaLink::createFromCallStackArray($attributes, $renderer->date_at);
20837748cd8SNickeau                    if ($media->isImage() || $media->getExtension() === "svg") {
20937748cd8SNickeau                        try {
210*1fa8c418SNickeau                            $renderer->doc .= $mediaLink->renderMediaTagWithLink();
21137748cd8SNickeau                        } catch (RuntimeException $e) {
21237748cd8SNickeau                            $errorClass = self::SVG_RENDERING_ERROR_CLASS;
21337748cd8SNickeau                            $message = "Media ({$media->getPath()}). Error while rendering: {$e->getMessage()}";
214*1fa8c418SNickeau                            $renderer->doc .= "<span class=\"text-alert $errorClass\">" . hsc(trim($message)) . "</span>";
215*1fa8c418SNickeau                            LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, MediaLink::CANONICAL);
21637748cd8SNickeau                        }
21723723136Sgerardnico                        return true;
21823723136Sgerardnico                    }
21923723136Sgerardnico                }
22021913ab3SNickeau
22121913ab3SNickeau                /**
22223723136Sgerardnico                 * This is not an local internal media image (a video or an url image)
22321913ab3SNickeau                 * Dokuwiki takes over
22421913ab3SNickeau                 */
225531e725cSNickeau                $type = $attributes[MediaLink::MEDIA_DOKUWIKI_TYPE];
22621913ab3SNickeau                $src = $attributes['src'];
22721913ab3SNickeau                $title = $attributes['title'];
22821913ab3SNickeau                $align = $attributes['align'];
22921913ab3SNickeau                $width = $attributes['width'];
23021913ab3SNickeau                $height = $attributes['height'];
23121913ab3SNickeau                $cache = $attributes['cache'];
232a6bf47aaSNickeau                if ($cache == null) {
233a6bf47aaSNickeau                    // Dokuwiki needs a value
234a6bf47aaSNickeau                    // If their is no value it will output it without any value
235a6bf47aaSNickeau                    // in the query string.
236a6bf47aaSNickeau                    $cache = "cache";
237a6bf47aaSNickeau                }
23821913ab3SNickeau                $linking = $attributes['linking'];
23923723136Sgerardnico                switch ($type) {
240531e725cSNickeau                    case MediaLink::INTERNAL_MEDIA_CALL_NAME:
24121913ab3SNickeau                        $renderer->doc .= $renderer->internalmedia($src, $title, $align, $width, $height, $cache, $linking, true);
24223723136Sgerardnico                        break;
243531e725cSNickeau                    case MediaLink::EXTERNAL_MEDIA_CALL_NAME:
24423723136Sgerardnico                        $renderer->doc .= $renderer->externalmedia($src, $title, $align, $width, $height, $cache, $linking, true);
24523723136Sgerardnico                        break;
24623723136Sgerardnico                    default:
24723723136Sgerardnico                        LogUtility::msg("The dokuwiki media type ($type) is unknown");
24823723136Sgerardnico                        break;
24921913ab3SNickeau                }
25021913ab3SNickeau
25123723136Sgerardnico                return true;
25221913ab3SNickeau
2539337a630SNickeau            case
2549337a630SNickeau            "metadata":
25521913ab3SNickeau
25621913ab3SNickeau                /**
25721913ab3SNickeau                 * Keep track of the metadata
25821913ab3SNickeau                 * @var Doku_Renderer_metadata $renderer
25921913ab3SNickeau                 */
26037748cd8SNickeau                $attributes = $data[PluginUtility::ATTRIBUTES];
26121913ab3SNickeau                self::registerImageMeta($attributes, $renderer);
26223723136Sgerardnico                return true;
26321913ab3SNickeau
264e8b2ff59SNickeau            case renderer_plugin_combo_analytics::RENDERER_FORMAT:
265e8b2ff59SNickeau
266e8b2ff59SNickeau                /**
267e8b2ff59SNickeau                 * Special pattern call
268e8b2ff59SNickeau                 * @var renderer_plugin_combo_analytics $renderer
269e8b2ff59SNickeau                 */
270e8b2ff59SNickeau                $attributes = $data[PluginUtility::ATTRIBUTES];
27137748cd8SNickeau                self::updateStatistics($attributes, $renderer);
272e8b2ff59SNickeau                return true;
273e8b2ff59SNickeau
27421913ab3SNickeau        }
27521913ab3SNickeau        // unsupported $mode
27621913ab3SNickeau        return false;
27721913ab3SNickeau    }
27821913ab3SNickeau
27921913ab3SNickeau    /**
28037748cd8SNickeau     * Update the index for the move plugin
28137748cd8SNickeau     * and {@link Page::FIRST_IMAGE_META_RELATION}
28237748cd8SNickeau     *
28321913ab3SNickeau     * @param array $attributes
28421913ab3SNickeau     * @param Doku_Renderer_metadata $renderer
28521913ab3SNickeau     */
28621913ab3SNickeau    static public function registerImageMeta($attributes, $renderer)
28721913ab3SNickeau    {
288531e725cSNickeau        $type = $attributes[MediaLink::MEDIA_DOKUWIKI_TYPE];
28921913ab3SNickeau        $src = $attributes['src'];
290531e725cSNickeau        if ($src == null) {
291531e725cSNickeau            $src = $attributes[DokuPath::PATH_ATTRIBUTE];
292531e725cSNickeau        }
29321913ab3SNickeau        $title = $attributes['title'];
29421913ab3SNickeau        $align = $attributes['align'];
29521913ab3SNickeau        $width = $attributes['width'];
29621913ab3SNickeau        $height = $attributes['height'];
29721913ab3SNickeau        $cache = $attributes['cache']; // Cache: https://www.dokuwiki.org/images#caching
29821913ab3SNickeau        $linking = $attributes['linking'];
29923723136Sgerardnico
30023723136Sgerardnico        switch ($type) {
301531e725cSNickeau            case MediaLink::INTERNAL_MEDIA_CALL_NAME:
30221913ab3SNickeau                $renderer->internalmedia($src, $title, $align, $width, $height, $cache, $linking);
30323723136Sgerardnico                break;
304531e725cSNickeau            case MediaLink::EXTERNAL_MEDIA_CALL_NAME:
30523723136Sgerardnico                $renderer->externalmedia($src, $title, $align, $width, $height, $cache, $linking);
30623723136Sgerardnico                break;
30723723136Sgerardnico            default:
30823723136Sgerardnico                LogUtility::msg("The dokuwiki media type ($type)  for metadata registration is unknown");
30923723136Sgerardnico                break;
31023723136Sgerardnico        }
31123723136Sgerardnico
31221913ab3SNickeau    }
31321913ab3SNickeau
31421913ab3SNickeau
31521913ab3SNickeau}
31621913ab3SNickeau
317