xref: /plugin/combo/ComboStrap/MediaLink.php (revision 4cadd4f8c541149bdda95f080e38a6d4e3a640ca)
137748cd8SNickeau<?php
237748cd8SNickeau/**
337748cd8SNickeau * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved.
437748cd8SNickeau *
537748cd8SNickeau * This source code is licensed under the GPL license found in the
637748cd8SNickeau * COPYING  file in the root directory of this source tree.
737748cd8SNickeau *
837748cd8SNickeau * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
937748cd8SNickeau * @author   ComboStrap <support@combostrap.com>
1037748cd8SNickeau *
1137748cd8SNickeau */
1237748cd8SNickeau
1337748cd8SNickeaunamespace ComboStrap;
1437748cd8SNickeau
15*4cadd4f8SNickeauuse dokuwiki\Action\Plugin;
1637748cd8SNickeauuse dokuwiki\Extension\SyntaxPlugin;
17c3437056SNickeauuse dokuwiki\Parsing\ParserMode\Internallink;
1837748cd8SNickeauuse syntax_plugin_combo_media;
1937748cd8SNickeau
201fa8c418SNickeaurequire_once(__DIR__ . '/PluginUtility.php');
2137748cd8SNickeau
2237748cd8SNickeau/**
2337748cd8SNickeau * Class InternalMedia
2437748cd8SNickeau * Represent a media link
2537748cd8SNickeau *
2637748cd8SNickeau *
2737748cd8SNickeau * @package ComboStrap
2837748cd8SNickeau *
2937748cd8SNickeau * Wrapper around {@link Doku_Handler_Parse_Media}
3037748cd8SNickeau *
3137748cd8SNickeau * Not that for dokuwiki the `type` key of the attributes is the `call`
3237748cd8SNickeau * and therefore determine the function in an render
3337748cd8SNickeau * (ie {@link \Doku_Renderer::internalmedialink()} or {@link \Doku_Renderer::externalmedialink()}
3437748cd8SNickeau *
351fa8c418SNickeau * This is a link to a media (pdf, image, ...).
361fa8c418SNickeau * It's used to check the media type and to
371fa8c418SNickeau * take over if the media type is an image
3837748cd8SNickeau */
391fa8c418SNickeauabstract class MediaLink
4037748cd8SNickeau{
4137748cd8SNickeau
4237748cd8SNickeau
4337748cd8SNickeau    /**
4437748cd8SNickeau     * The dokuwiki type and mode name
4537748cd8SNickeau     * (ie call)
4637748cd8SNickeau     *  * ie {@link MediaLink::EXTERNAL_MEDIA_CALL_NAME}
4737748cd8SNickeau     *  or {@link MediaLink::INTERNAL_MEDIA_CALL_NAME}
4837748cd8SNickeau     *
4937748cd8SNickeau     * The dokuwiki type (internalmedia/externalmedia)
5037748cd8SNickeau     * is saved in a `type` key that clash with the
5137748cd8SNickeau     * combostrap type. To avoid the clash, we renamed it
5237748cd8SNickeau     */
5337748cd8SNickeau    const MEDIA_DOKUWIKI_TYPE = 'dokuwiki_type';
5437748cd8SNickeau    const INTERNAL_MEDIA_CALL_NAME = "internalmedia";
5537748cd8SNickeau    const EXTERNAL_MEDIA_CALL_NAME = "externalmedia";
5637748cd8SNickeau
5737748cd8SNickeau    const CANONICAL = "image";
5837748cd8SNickeau
5937748cd8SNickeau    /**
6037748cd8SNickeau     * This attributes does not apply
6137748cd8SNickeau     * to a URL
6237748cd8SNickeau     * They are only for the tag (img, svg, ...)
6337748cd8SNickeau     * or internal
6437748cd8SNickeau     */
6537748cd8SNickeau    const NON_URL_ATTRIBUTES = [
661fa8c418SNickeau        MediaLink::ALIGN_KEY,
671fa8c418SNickeau        MediaLink::LINKING_KEY,
6837748cd8SNickeau        TagAttributes::TITLE_KEY,
6937748cd8SNickeau        Hover::ON_HOVER_ATTRIBUTE,
7037748cd8SNickeau        Animation::ON_VIEW_ATTRIBUTE,
7137748cd8SNickeau        MediaLink::MEDIA_DOKUWIKI_TYPE,
7237748cd8SNickeau        MediaLink::DOKUWIKI_SRC
7337748cd8SNickeau    ];
7437748cd8SNickeau
7537748cd8SNickeau    /**
7637748cd8SNickeau     * This attribute applies
7737748cd8SNickeau     * to a image url (img, svg, ...)
7837748cd8SNickeau     */
7937748cd8SNickeau    const URL_ATTRIBUTES = [
8037748cd8SNickeau        Dimension::WIDTH_KEY,
8137748cd8SNickeau        Dimension::HEIGHT_KEY,
8237748cd8SNickeau        CacheMedia::CACHE_KEY,
8337748cd8SNickeau    ];
8437748cd8SNickeau
8537748cd8SNickeau    /**
8637748cd8SNickeau     * Default image linking value
8737748cd8SNickeau     */
8837748cd8SNickeau    const CONF_DEFAULT_LINKING = "defaultImageLinking";
8937748cd8SNickeau    const LINKING_LINKONLY_VALUE = "linkonly";
9037748cd8SNickeau    const LINKING_DETAILS_VALUE = 'details';
9137748cd8SNickeau    const LINKING_NOLINK_VALUE = 'nolink';
9237748cd8SNickeau
9337748cd8SNickeau    /**
9437748cd8SNickeau     * @deprecated 2021-06-12
9537748cd8SNickeau     */
9637748cd8SNickeau    const LINK_PATTERN = "{{\s*([^|\s]*)\s*\|?.*}}";
9737748cd8SNickeau
9837748cd8SNickeau    const LINKING_DIRECT_VALUE = 'direct';
9937748cd8SNickeau
10037748cd8SNickeau    /**
10137748cd8SNickeau     * Only used by Dokuwiki
10237748cd8SNickeau     * Contains the path and eventually an anchor
10337748cd8SNickeau     * never query parameters
10437748cd8SNickeau     */
10537748cd8SNickeau    const DOKUWIKI_SRC = "src";
10637748cd8SNickeau    /**
10737748cd8SNickeau     * Link value:
10837748cd8SNickeau     *   * 'nolink'
10937748cd8SNickeau     *   * 'direct': directly to the image
11037748cd8SNickeau     *   * 'linkonly': show only a url
11137748cd8SNickeau     *   * 'details': go to the details media viewer
11237748cd8SNickeau     *
11337748cd8SNickeau     * @var
11437748cd8SNickeau     */
11537748cd8SNickeau    const LINKING_KEY = 'linking';
11637748cd8SNickeau    const ALIGN_KEY = 'align';
11737748cd8SNickeau
118*4cadd4f8SNickeau    /**
119*4cadd4f8SNickeau     * The method to lazy load resources (Ie media)
120*4cadd4f8SNickeau     */
121*4cadd4f8SNickeau    const LAZY_LOAD_METHOD = "lazy-method";
122*4cadd4f8SNickeau    const LAZY_LOAD_METHOD_HTML_VALUE = "html-attribute";
123*4cadd4f8SNickeau    const LAZY_LOAD_METHOD_LOZAD_VALUE = "lozad";
124*4cadd4f8SNickeau    const UNKNOWN_MIME = "unknwon";
125*4cadd4f8SNickeau    /**
126*4cadd4f8SNickeau     * @var string
127*4cadd4f8SNickeau     */
128*4cadd4f8SNickeau    private $lazyLoadMethod;
12937748cd8SNickeau
13037748cd8SNickeau    private $lazyLoad = null;
13137748cd8SNickeau
13237748cd8SNickeau
13337748cd8SNickeau    /**
1341fa8c418SNickeau     * The path of the media
1351fa8c418SNickeau     * @var Media[]
13637748cd8SNickeau     */
1371fa8c418SNickeau    private $media;
138*4cadd4f8SNickeau    private $linking;
139*4cadd4f8SNickeau    private $linkingClass;
14037748cd8SNickeau
14137748cd8SNickeau
14237748cd8SNickeau    /**
14337748cd8SNickeau     * Image constructor.
1441fa8c418SNickeau     * @param Image $media
14537748cd8SNickeau     *
14637748cd8SNickeau     * Protected and not private
14737748cd8SNickeau     * to allow cascading init
14837748cd8SNickeau     * If private, the parent attributes are null
14937748cd8SNickeau     */
1501fa8c418SNickeau    protected function __construct(Media $media)
15137748cd8SNickeau    {
1521fa8c418SNickeau        $this->media = $media;
15337748cd8SNickeau    }
15437748cd8SNickeau
15537748cd8SNickeau
15637748cd8SNickeau    /**
157c3437056SNickeau     * Create an image from dokuwiki {@link Internallink internal call media attributes}
158c3437056SNickeau     *
159c3437056SNickeau     * Dokuwiki extracts already the width, height and align property
16037748cd8SNickeau     * @param array $callAttributes
16137748cd8SNickeau     * @return MediaLink
16237748cd8SNickeau     */
16337748cd8SNickeau    public static function createFromIndexAttributes(array $callAttributes)
16437748cd8SNickeau    {
165c3437056SNickeau        $src = $callAttributes[0];
16637748cd8SNickeau        $title = $callAttributes[1];
16737748cd8SNickeau        $align = $callAttributes[2];
16837748cd8SNickeau        $width = $callAttributes[3];
16937748cd8SNickeau        $height = $callAttributes[4];
17037748cd8SNickeau        $cache = $callAttributes[5];
17137748cd8SNickeau        $linking = $callAttributes[6];
17237748cd8SNickeau
17337748cd8SNickeau        $tagAttributes = TagAttributes::createEmpty();
17437748cd8SNickeau        $tagAttributes->addComponentAttributeValue(TagAttributes::TITLE_KEY, $title);
17537748cd8SNickeau        $tagAttributes->addComponentAttributeValue(self::ALIGN_KEY, $align);
17637748cd8SNickeau        $tagAttributes->addComponentAttributeValue(Dimension::WIDTH_KEY, $width);
17737748cd8SNickeau        $tagAttributes->addComponentAttributeValue(Dimension::HEIGHT_KEY, $height);
17837748cd8SNickeau        $tagAttributes->addComponentAttributeValue(CacheMedia::CACHE_KEY, $cache);
17937748cd8SNickeau        $tagAttributes->addComponentAttributeValue(self::LINKING_KEY, $linking);
18037748cd8SNickeau
181c3437056SNickeau        return self::createMediaLinkFromId($src, $tagAttributes);
18237748cd8SNickeau
18337748cd8SNickeau    }
18437748cd8SNickeau
18537748cd8SNickeau    /**
18637748cd8SNickeau     * A function to explicitly create an internal media from
18737748cd8SNickeau     * a call stack array (ie key string and value) that we get in the {@link SyntaxPlugin::render()}
18837748cd8SNickeau     * from the {@link MediaLink::toCallStackArray()}
18937748cd8SNickeau     *
19037748cd8SNickeau     * @param $attributes - the attributes created by the function {@link MediaLink::getParseAttributes()}
19137748cd8SNickeau     * @param $rev - the mtime
192c3437056SNickeau     * @return null|MediaLink
19337748cd8SNickeau     */
194c3437056SNickeau    public static function createFromCallStackArray($attributes, $rev = null): ?MediaLink
19537748cd8SNickeau    {
19637748cd8SNickeau
19737748cd8SNickeau        if (!is_array($attributes)) {
19837748cd8SNickeau            // Debug for the key_exist below because of the following message:
19937748cd8SNickeau            // `PHP Warning:  key_exists() expects parameter 2 to be array, array given`
20037748cd8SNickeau            LogUtility::msg("The `attributes` parameter is not an array. Value ($attributes)", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
20137748cd8SNickeau        }
20237748cd8SNickeau
20337748cd8SNickeau        $tagAttributes = TagAttributes::createFromCallStackArray($attributes);
20437748cd8SNickeau
205c3437056SNickeau        $src = $attributes[self::DOKUWIKI_SRC];
206c3437056SNickeau        if ($src === null) {
207c3437056SNickeau            /**
208c3437056SNickeau             * Dokuwiki parse already the src and create the path and the attributes
209c3437056SNickeau             * The new model will not, we check if we are in the old mode
210c3437056SNickeau             */
211c3437056SNickeau            $src = $attributes[PagePath::PROPERTY_NAME];
212c3437056SNickeau            if ($src === null) {
213c3437056SNickeau                LogUtility::msg("src is mandatory for an image link and was not passed");
214c3437056SNickeau                return null;
215c3437056SNickeau            }
216c3437056SNickeau        }
217c3437056SNickeau        $dokuUrl = DokuwikiUrl::createFromUrl($src);
218c3437056SNickeau        $scheme = $dokuUrl->getScheme();
219c3437056SNickeau        switch ($scheme) {
220c3437056SNickeau            case DokuFs::SCHEME:
221c3437056SNickeau                $id = $dokuUrl->getPath();
222c3437056SNickeau                // the id is always absolute, except in a link
223c3437056SNickeau                // It may be relative, transform it as absolute
224c3437056SNickeau                global $ID;
225c3437056SNickeau                resolve_mediaid(getNS($ID), $id, $exists);
226c3437056SNickeau                $path = DokuPath::createMediaPathFromId($id, $rev);
227c3437056SNickeau                return self::createMediaLinkFromPath($path, $tagAttributes);
228c3437056SNickeau            case InterWikiPath::scheme:
229c3437056SNickeau                $path = InterWikiPath::create($dokuUrl->getPath());
230c3437056SNickeau                return self::createMediaLinkFromPath($path, $tagAttributes);
231c3437056SNickeau            case InternetPath::scheme:
232c3437056SNickeau                $path = InternetPath::create($dokuUrl->getPath());
233c3437056SNickeau                return self::createMediaLinkFromPath($path, $tagAttributes);
234c3437056SNickeau            default:
235c3437056SNickeau                LogUtility::msg("The media with the scheme ($scheme) are not yet supported. Media Source: $src");
236c3437056SNickeau                return null;
23737748cd8SNickeau
238c3437056SNickeau        }
239c3437056SNickeau
24037748cd8SNickeau
24137748cd8SNickeau    }
24237748cd8SNickeau
24337748cd8SNickeau    /**
24437748cd8SNickeau     * @param $match - the match of the renderer (just a shortcut)
24537748cd8SNickeau     * @return MediaLink
24637748cd8SNickeau     */
24737748cd8SNickeau    public static function createFromRenderMatch($match)
24837748cd8SNickeau    {
24937748cd8SNickeau
25037748cd8SNickeau        /**
25137748cd8SNickeau         * The parsing function {@link Doku_Handler_Parse_Media} has some flow / problem
25237748cd8SNickeau         *    * It keeps the anchor only if there is no query string
25337748cd8SNickeau         *    * It takes the first digit as the width (ie media.pdf?page=31 would have a width of 31)
25437748cd8SNickeau         *    * `src` is not only the media path but may have a anchor
25537748cd8SNickeau         * We parse it then
25637748cd8SNickeau         */
25737748cd8SNickeau
25837748cd8SNickeau
25937748cd8SNickeau        /**
26037748cd8SNickeau         *   * Delete the opening and closing character
26137748cd8SNickeau         *   * create the url and description
26237748cd8SNickeau         */
26337748cd8SNickeau        $match = preg_replace(array('/^\{\{/', '/\}\}$/u'), '', $match);
26437748cd8SNickeau        $parts = explode('|', $match, 2);
26537748cd8SNickeau        $description = null;
26637748cd8SNickeau        $url = $parts[0];
26737748cd8SNickeau        if (isset($parts[1])) {
26837748cd8SNickeau            $description = $parts[1];
26937748cd8SNickeau        }
27037748cd8SNickeau
27137748cd8SNickeau        /**
27237748cd8SNickeau         * Media Alignment
27337748cd8SNickeau         */
27437748cd8SNickeau        $rightAlign = (bool)preg_match('/^ /', $url);
27537748cd8SNickeau        $leftAlign = (bool)preg_match('/ $/', $url);
27637748cd8SNickeau        $url = trim($url);
27737748cd8SNickeau
27837748cd8SNickeau        // Logic = what's that ;)...
27937748cd8SNickeau        if ($leftAlign & $rightAlign) {
28037748cd8SNickeau            $align = 'center';
28137748cd8SNickeau        } else if ($rightAlign) {
28237748cd8SNickeau            $align = 'right';
28337748cd8SNickeau        } else if ($leftAlign) {
28437748cd8SNickeau            $align = 'left';
28537748cd8SNickeau        } else {
28637748cd8SNickeau            $align = null;
28737748cd8SNickeau        }
28837748cd8SNickeau
28937748cd8SNickeau        /**
29037748cd8SNickeau         * The combo attributes array
29137748cd8SNickeau         */
292c3437056SNickeau        $dokuwikiUrl = DokuwikiUrl::createFromUrl($url);
293c3437056SNickeau        $parsedAttributes = $dokuwikiUrl->toArray();
294c3437056SNickeau        $path = $dokuwikiUrl->getPath();
295c3437056SNickeau        $linkingKey = $dokuwikiUrl->getQueryParameter(MediaLink::LINKING_KEY);
296c3437056SNickeau        if ($linkingKey === null) {
297c3437056SNickeau            $linkingKey = PluginUtility::getConfValue(self::CONF_DEFAULT_LINKING, self::LINKING_DIRECT_VALUE);
29837748cd8SNickeau        }
299c3437056SNickeau        $parsedAttributes[MediaLink::LINKING_KEY] = $linkingKey;
30037748cd8SNickeau
30137748cd8SNickeau        /**
30237748cd8SNickeau         * Media Type
30337748cd8SNickeau         */
304c3437056SNickeau        $scheme = $dokuwikiUrl->getScheme();
305c3437056SNickeau        if ($scheme === DokuFs::SCHEME) {
30637748cd8SNickeau            $mediaType = MediaLink::INTERNAL_MEDIA_CALL_NAME;
307c3437056SNickeau        } else {
308c3437056SNickeau            $mediaType = MediaLink::EXTERNAL_MEDIA_CALL_NAME;
30937748cd8SNickeau        }
31037748cd8SNickeau
31137748cd8SNickeau
31237748cd8SNickeau        /**
31337748cd8SNickeau         * src in dokuwiki is the path and the anchor if any
31437748cd8SNickeau         */
31537748cd8SNickeau        $src = $path;
31637748cd8SNickeau        if (isset($parsedAttributes[DokuwikiUrl::ANCHOR_ATTRIBUTES]) != null) {
31737748cd8SNickeau            $src = $src . "#" . $parsedAttributes[DokuwikiUrl::ANCHOR_ATTRIBUTES];
31837748cd8SNickeau        }
31937748cd8SNickeau
32037748cd8SNickeau        /**
32137748cd8SNickeau         * To avoid clash with the combostrap component type
32237748cd8SNickeau         * ie this is also a ComboStrap attribute where we set the type of a SVG (icon, illustration, background)
32337748cd8SNickeau         * we store the media type (ie external/internal) in another key
32437748cd8SNickeau         *
32537748cd8SNickeau         * There is no need to repeat the attributes as the arrays are merged
32637748cd8SNickeau         * into on but this is also an informal code to show which attributes
32737748cd8SNickeau         * are only Dokuwiki Native
32837748cd8SNickeau         *
32937748cd8SNickeau         */
33037748cd8SNickeau        $dokuwikiAttributes = array(
33137748cd8SNickeau            self::MEDIA_DOKUWIKI_TYPE => $mediaType,
33237748cd8SNickeau            self::DOKUWIKI_SRC => $src,
33337748cd8SNickeau            Dimension::WIDTH_KEY => $parsedAttributes[Dimension::WIDTH_KEY],
33437748cd8SNickeau            Dimension::HEIGHT_KEY => $parsedAttributes[Dimension::HEIGHT_KEY],
33537748cd8SNickeau            CacheMedia::CACHE_KEY => $parsedAttributes[CacheMedia::CACHE_KEY],
3361fa8c418SNickeau            TagAttributes::TITLE_KEY => $description,
33737748cd8SNickeau            MediaLink::ALIGN_KEY => $align,
33837748cd8SNickeau            MediaLink::LINKING_KEY => $parsedAttributes[MediaLink::LINKING_KEY],
33937748cd8SNickeau        );
34037748cd8SNickeau
34137748cd8SNickeau        /**
34237748cd8SNickeau         * Merge standard dokuwiki attributes and
34337748cd8SNickeau         * parsed attributes
34437748cd8SNickeau         */
34537748cd8SNickeau        $mergedAttributes = PluginUtility::mergeAttributes($dokuwikiAttributes, $parsedAttributes);
34637748cd8SNickeau
34737748cd8SNickeau        /**
34837748cd8SNickeau         * If this is an internal media,
34937748cd8SNickeau         * we are using our implementation
35037748cd8SNickeau         * and we have a change on attribute specification
35137748cd8SNickeau         */
35237748cd8SNickeau        if ($mediaType == MediaLink::INTERNAL_MEDIA_CALL_NAME) {
35337748cd8SNickeau
35437748cd8SNickeau            /**
35537748cd8SNickeau             * The align attribute on an image parse
35637748cd8SNickeau             * is a float right
35737748cd8SNickeau             * ComboStrap does a difference between a block right and a float right
35837748cd8SNickeau             */
35937748cd8SNickeau            if ($mergedAttributes[self::ALIGN_KEY] === "right") {
36037748cd8SNickeau                unset($mergedAttributes[self::ALIGN_KEY]);
36137748cd8SNickeau                $mergedAttributes[FloatAttribute::FLOAT_KEY] = "right";
36237748cd8SNickeau            }
36337748cd8SNickeau
36437748cd8SNickeau
36537748cd8SNickeau        }
36637748cd8SNickeau
36737748cd8SNickeau        return self::createFromCallStackArray($mergedAttributes);
36837748cd8SNickeau
36937748cd8SNickeau    }
37037748cd8SNickeau
37137748cd8SNickeau
37237748cd8SNickeau    public
373c3437056SNickeau    function setLazyLoad($false): MediaLink
37437748cd8SNickeau    {
37537748cd8SNickeau        $this->lazyLoad = $false;
376c3437056SNickeau        return $this;
37737748cd8SNickeau    }
37837748cd8SNickeau
37937748cd8SNickeau    public
38037748cd8SNickeau    function getLazyLoad()
38137748cd8SNickeau    {
38237748cd8SNickeau        return $this->lazyLoad;
38337748cd8SNickeau    }
38437748cd8SNickeau
38537748cd8SNickeau
38637748cd8SNickeau    /**
387c3437056SNickeau     * Create a media link from a wiki id
38837748cd8SNickeau     *
38937748cd8SNickeau     *
390c3437056SNickeau     * @param $wikiId - dokuwiki id
391c3437056SNickeau     * @param TagAttributes|null $tagAttributes
392c3437056SNickeau     * @param string|null $rev
39337748cd8SNickeau     * @return MediaLink
39437748cd8SNickeau     */
39537748cd8SNickeau    public
396c3437056SNickeau    static function createMediaLinkFromId($wikiId, ?string $rev = '', TagAttributes $tagAttributes = null)
39737748cd8SNickeau    {
39837748cd8SNickeau        if (is_object($rev)) {
39937748cd8SNickeau            LogUtility::msg("rev should not be an object", LogUtility::LVL_MSG_ERROR, "support");
40037748cd8SNickeau        }
40137748cd8SNickeau        if ($tagAttributes == null) {
40237748cd8SNickeau            $tagAttributes = TagAttributes::createEmpty();
40337748cd8SNickeau        } else {
40437748cd8SNickeau            if (!($tagAttributes instanceof TagAttributes)) {
40537748cd8SNickeau                LogUtility::msg("TagAttributes is not an instance of Tag Attributes", LogUtility::LVL_MSG_ERROR, "support");
40637748cd8SNickeau            }
40737748cd8SNickeau        }
40837748cd8SNickeau
409c3437056SNickeau        $dokuPath = DokuPath::createMediaPathFromId($wikiId, $rev);
410c3437056SNickeau        return self::createMediaLinkFromPath($dokuPath, $tagAttributes);
411c3437056SNickeau
412c3437056SNickeau    }
413c3437056SNickeau
41437748cd8SNickeau    /**
415c3437056SNickeau     * @param Path $path
416*4cadd4f8SNickeau     * @param TagAttributes|null $tagAttributes
417c3437056SNickeau     * @return RasterImageLink|SvgImageLink|ThirdMediaLink
41837748cd8SNickeau     */
419*4cadd4f8SNickeau    public static function createMediaLinkFromPath(Path $path, TagAttributes $tagAttributes = null)
4201fa8c418SNickeau    {
421c3437056SNickeau
422*4cadd4f8SNickeau        if ($tagAttributes === null) {
423*4cadd4f8SNickeau            $tagAttributes = TagAttributes::createEmpty();
424*4cadd4f8SNickeau        }
425*4cadd4f8SNickeau
426*4cadd4f8SNickeau        /**
427*4cadd4f8SNickeau         * Get and delete the attribute for the link
428*4cadd4f8SNickeau         * (The rest is for the image)
429*4cadd4f8SNickeau         */
430*4cadd4f8SNickeau        $lazyLoadMethod = $tagAttributes->getValueAndRemoveIfPresent(self::LAZY_LOAD_METHOD, self::LAZY_LOAD_METHOD_LOZAD_VALUE);
431*4cadd4f8SNickeau        $linking = $tagAttributes->getValueAndRemoveIfPresent(self::LINKING_KEY);
432*4cadd4f8SNickeau        $linkingClass = $tagAttributes->getValueAndRemoveIfPresent(syntax_plugin_combo_media::LINK_CLASS_ATTRIBUTE);
433*4cadd4f8SNickeau
43437748cd8SNickeau        /**
43537748cd8SNickeau         * Processing
43637748cd8SNickeau         */
437c3437056SNickeau        $mime = $path->getMime();
438c3437056SNickeau        if ($path->getExtension() === "svg") {
43937748cd8SNickeau            /**
44037748cd8SNickeau             * The mime type is set when uploading, not when
44137748cd8SNickeau             * viewing.
44237748cd8SNickeau             * Because they are internal image, the svg was already uploaded
44337748cd8SNickeau             * Therefore, no authorization scheme here
44437748cd8SNickeau             */
445c3437056SNickeau            $mime = Mime::create(Mime::SVG);
44637748cd8SNickeau        }
44737748cd8SNickeau
448c3437056SNickeau        if ($mime === null) {
449*4cadd4f8SNickeau            $stringMime = self::UNKNOWN_MIME;
450*4cadd4f8SNickeau        } else {
451*4cadd4f8SNickeau            $stringMime = $mime->toString();
45237748cd8SNickeau        }
45337748cd8SNickeau
454*4cadd4f8SNickeau        switch ($stringMime) {
455*4cadd4f8SNickeau            case self::UNKNOWN_MIME:
456*4cadd4f8SNickeau                LogUtility::msg("The mime type of the media ($path) is <a href=\"https://www.dokuwiki.org/mime\">unknown (not in the configuration file)</a>", LogUtility::LVL_MSG_ERROR);
457*4cadd4f8SNickeau                $media = new ImageRaster($path, $tagAttributes);
458*4cadd4f8SNickeau                $mediaLink = new RasterImageLink($media);
459*4cadd4f8SNickeau                break;
460*4cadd4f8SNickeau            case Mime::SVG:
461*4cadd4f8SNickeau                $media = new ImageSvg($path, $tagAttributes);
462*4cadd4f8SNickeau                $mediaLink = new SvgImageLink($media);
463*4cadd4f8SNickeau                break;
464*4cadd4f8SNickeau            default:
465c3437056SNickeau                if (!$mime->isImage()) {
466c3437056SNickeau                    LogUtility::msg("The type ($mime) of media ($path) is not an image", LogUtility::LVL_MSG_DEBUG, "image");
467c3437056SNickeau                    $media = new ThirdMedia($path, $tagAttributes);
468*4cadd4f8SNickeau                    $mediaLink = new ThirdMediaLink($media);
469*4cadd4f8SNickeau                } else {
470c3437056SNickeau                    $media = new ImageRaster($path, $tagAttributes);
471*4cadd4f8SNickeau                    $mediaLink = new RasterImageLink($media);
472*4cadd4f8SNickeau                }
473*4cadd4f8SNickeau                break;
474*4cadd4f8SNickeau        }
475c3437056SNickeau
476*4cadd4f8SNickeau        $mediaLink
477*4cadd4f8SNickeau            ->setLazyLoadMethod($lazyLoadMethod)
478*4cadd4f8SNickeau            ->setLinking($linking)
479*4cadd4f8SNickeau            ->setLinkingClass($linkingClass);
480*4cadd4f8SNickeau        return $mediaLink;
481c3437056SNickeau
48237748cd8SNickeau    }
48337748cd8SNickeau
484*4cadd4f8SNickeau    public function setLazyLoadMethod(string $lazyLoadMethod): MediaLink
485*4cadd4f8SNickeau    {
486*4cadd4f8SNickeau        $this->lazyLoadMethod = $lazyLoadMethod;
487*4cadd4f8SNickeau        return $this;
488*4cadd4f8SNickeau    }
489*4cadd4f8SNickeau
49037748cd8SNickeau
49137748cd8SNickeau    /**
49237748cd8SNickeau     * A function to set explicitly which array format
49337748cd8SNickeau     * is used in the returned data of a {@link SyntaxPlugin::handle()}
49437748cd8SNickeau     * (which ultimately is stored in the {@link CallStack)
49537748cd8SNickeau     *
49637748cd8SNickeau     * This is to make the difference with the {@link MediaLink::createFromIndexAttributes()}
49737748cd8SNickeau     * that is indexed by number (ie without property name)
49837748cd8SNickeau     *
49937748cd8SNickeau     *
50037748cd8SNickeau     * Return the same array than with the {@link self::parse()} method
50137748cd8SNickeau     * that is used in the {@link CallStack}
50237748cd8SNickeau     *
50337748cd8SNickeau     * @return array of key string and value
50437748cd8SNickeau     */
505c3437056SNickeau    public
506c3437056SNickeau    function toCallStackArray(): array
50737748cd8SNickeau    {
50837748cd8SNickeau        /**
50937748cd8SNickeau         * Trying to stay inline with the dokuwiki key
51037748cd8SNickeau         * We use the 'src' attributes as id
51137748cd8SNickeau         *
51237748cd8SNickeau         * src is a path (not an id)
51337748cd8SNickeau         */
51437748cd8SNickeau        $array = array(
515*4cadd4f8SNickeau            PagePath::PROPERTY_NAME => $this->getMedia()->getPath()->toString(),
516*4cadd4f8SNickeau            self::LINKING_KEY => $this->getLinking()
51737748cd8SNickeau        );
51837748cd8SNickeau
51937748cd8SNickeau
52037748cd8SNickeau        // Add the extra attribute
5211fa8c418SNickeau        return array_merge($this->getMedia()->getAttributes()->toCallStackArray(), $array);
52237748cd8SNickeau
52337748cd8SNickeau
52437748cd8SNickeau    }
52537748cd8SNickeau
52637748cd8SNickeau
52737748cd8SNickeau    public
52837748cd8SNickeau    static function isInternalMediaSyntax($text)
52937748cd8SNickeau    {
53037748cd8SNickeau        return preg_match(' / ' . syntax_plugin_combo_media::MEDIA_PATTERN . ' / msSi', $text);
53137748cd8SNickeau    }
53237748cd8SNickeau
53337748cd8SNickeau
53437748cd8SNickeau    public
53537748cd8SNickeau    function __toString()
53637748cd8SNickeau    {
537c3437056SNickeau        $media = $this->getMedia();
538c3437056SNickeau        $dokuPath = $media->getPath();
539c3437056SNickeau        if ($dokuPath !== null) {
540c3437056SNickeau            return $dokuPath->getDokuwikiId();
541c3437056SNickeau        } else {
542c3437056SNickeau            return $media->__toString();
543c3437056SNickeau        }
54437748cd8SNickeau    }
54537748cd8SNickeau
54637748cd8SNickeau
54737748cd8SNickeau    private
54837748cd8SNickeau    function getLinking()
54937748cd8SNickeau    {
550*4cadd4f8SNickeau        return $this->linking;
55137748cd8SNickeau    }
55237748cd8SNickeau
553*4cadd4f8SNickeau    private
554*4cadd4f8SNickeau    function setLinking($value): MediaLink
555*4cadd4f8SNickeau    {
556*4cadd4f8SNickeau        $this->linking = $value;
557*4cadd4f8SNickeau        return $this;
558*4cadd4f8SNickeau    }
559*4cadd4f8SNickeau
560*4cadd4f8SNickeau    private
561*4cadd4f8SNickeau    function getLinkingClass()
562*4cadd4f8SNickeau    {
563*4cadd4f8SNickeau        return $this->linkingClass;
564*4cadd4f8SNickeau    }
565*4cadd4f8SNickeau
566*4cadd4f8SNickeau    private
567*4cadd4f8SNickeau    function setLinkingClass($value): MediaLink
568*4cadd4f8SNickeau    {
569*4cadd4f8SNickeau        $this->linkingClass = $value;
570*4cadd4f8SNickeau        return $this;
571*4cadd4f8SNickeau    }
57237748cd8SNickeau
57337748cd8SNickeau    /**
57437748cd8SNickeau     * @return string - the HTML of the image inside a link if asked
57537748cd8SNickeau     */
57637748cd8SNickeau    public
5771fa8c418SNickeau    function renderMediaTagWithLink(): string
57837748cd8SNickeau    {
57937748cd8SNickeau
58037748cd8SNickeau        /**
58137748cd8SNickeau         * Link to the media
58237748cd8SNickeau         *
58337748cd8SNickeau         */
5841fa8c418SNickeau        $mediaLink = TagAttributes::createEmpty();
58537748cd8SNickeau        // https://www.dokuwiki.org/config:target
58637748cd8SNickeau        global $conf;
58737748cd8SNickeau        $target = $conf['target']['media'];
588*4cadd4f8SNickeau        $mediaLink->addOutputAttributeValueIfNotEmpty("target", $target);
58937748cd8SNickeau        if (!empty($target)) {
590*4cadd4f8SNickeau            $mediaLink->addOutputAttributeValue("rel", 'noopener');
59137748cd8SNickeau        }
59237748cd8SNickeau
59337748cd8SNickeau        /**
59437748cd8SNickeau         * Do we add a link to the image ?
59537748cd8SNickeau         */
5961fa8c418SNickeau        $media = $this->getMedia();
597c3437056SNickeau        $dokuPath = $media->getPath();
598c3437056SNickeau        if (!($dokuPath instanceof DokuPath)) {
599c3437056SNickeau            LogUtility::msg("Media Link are only supported on media from the internal library ($media)", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
600c3437056SNickeau            return "";
601c3437056SNickeau        }
6021fa8c418SNickeau        $linking = $this->getLinking();
60337748cd8SNickeau        switch ($linking) {
60437748cd8SNickeau            case self::LINKING_LINKONLY_VALUE: // show only a url
60537748cd8SNickeau                $src = ml(
606c3437056SNickeau                    $dokuPath->getDokuwikiId(),
60737748cd8SNickeau                    array(
608c3437056SNickeau                        'id' => $dokuPath->getDokuwikiId(),
6091fa8c418SNickeau                        'cache' => $media->getCache(),
610c3437056SNickeau                        'rev' => $dokuPath->getRevision()
61137748cd8SNickeau                    )
61237748cd8SNickeau                );
613*4cadd4f8SNickeau                $mediaLink->addOutputAttributeValue("href", $src);
6141fa8c418SNickeau                $title = $media->getTitle();
61537748cd8SNickeau                if (empty($title)) {
616c3437056SNickeau                    $title = $media->getType();
61737748cd8SNickeau                }
6181fa8c418SNickeau                return $mediaLink->toHtmlEnterTag("a") . $title . "</a>";
61937748cd8SNickeau            case self::LINKING_NOLINK_VALUE:
62037748cd8SNickeau                return $this->renderMediaTag();
62137748cd8SNickeau            default:
62237748cd8SNickeau            case self::LINKING_DIRECT_VALUE:
62337748cd8SNickeau                //directly to the image
62437748cd8SNickeau                $src = ml(
625c3437056SNickeau                    $dokuPath->getDokuwikiId(),
62637748cd8SNickeau                    array(
627c3437056SNickeau                        'id' => $dokuPath->getDokuwikiId(),
6281fa8c418SNickeau                        'cache' => $media->getCache(),
629c3437056SNickeau                        'rev' => $dokuPath->getRevision()
63037748cd8SNickeau                    ),
63137748cd8SNickeau                    true
63237748cd8SNickeau                );
633*4cadd4f8SNickeau                $mediaLink->addOutputAttributeValue("href", $src);
634*4cadd4f8SNickeau                $snippetId = "lightbox";
635*4cadd4f8SNickeau                $mediaLink->addClassName("{$snippetId}-combo");
636*4cadd4f8SNickeau                $linkingClass = $this->getLinkingClass();
637*4cadd4f8SNickeau                if ($linkingClass !== null) {
638*4cadd4f8SNickeau                    $mediaLink->addClassName($linkingClass);
639*4cadd4f8SNickeau                }
640*4cadd4f8SNickeau                $snippetManager = PluginUtility::getSnippetManager();
641*4cadd4f8SNickeau                $snippetManager->attachJavascriptComboLibrary();
642*4cadd4f8SNickeau                $snippetManager->attachInternalJavascriptForSlot("lightbox");
643*4cadd4f8SNickeau                $snippetManager->attachCssInternalStyleSheetForSlot("lightbox");
644c3437056SNickeau                return $mediaLink->toHtmlEnterTag("a") . $this->renderMediaTag() . "</a>";
64537748cd8SNickeau
64637748cd8SNickeau            case self::LINKING_DETAILS_VALUE:
64737748cd8SNickeau                //go to the details media viewer
64837748cd8SNickeau                $src = ml(
649c3437056SNickeau                    $dokuPath->getDokuwikiId(),
65037748cd8SNickeau                    array(
651c3437056SNickeau                        'id' => $dokuPath->getDokuwikiId(),
6521fa8c418SNickeau                        'cache' => $media->getCache(),
653c3437056SNickeau                        'rev' => $dokuPath->getRevision()
65437748cd8SNickeau                    ),
65537748cd8SNickeau                    false
65637748cd8SNickeau                );
657*4cadd4f8SNickeau                $mediaLink->addOutputAttributeValue("href", $src);
6581fa8c418SNickeau                return $mediaLink->toHtmlEnterTag("a") .
65937748cd8SNickeau                    $this->renderMediaTag() .
66037748cd8SNickeau                    "</a>";
66137748cd8SNickeau
66237748cd8SNickeau        }
66337748cd8SNickeau
66437748cd8SNickeau
66537748cd8SNickeau    }
66637748cd8SNickeau
66737748cd8SNickeau
66837748cd8SNickeau    /**
66937748cd8SNickeau     * @return string - the HTML of the image
67037748cd8SNickeau     */
671c3437056SNickeau    public
672c3437056SNickeau
673c3437056SNickeau    abstract function renderMediaTag(): string;
6741fa8c418SNickeau
67537748cd8SNickeau
67637748cd8SNickeau    /**
6771fa8c418SNickeau     * The file
6781fa8c418SNickeau     * @return Media
67937748cd8SNickeau     */
6801fa8c418SNickeau    public function getMedia(): Media
6811fa8c418SNickeau    {
6821fa8c418SNickeau        return $this->media;
6831fa8c418SNickeau    }
68437748cd8SNickeau
685*4cadd4f8SNickeau    protected function getLazyLoadMethod(): string
686*4cadd4f8SNickeau    {
687*4cadd4f8SNickeau        return $this->lazyLoadMethod;
688*4cadd4f8SNickeau    }
68937748cd8SNickeau
69082a60d03SNickeau
69137748cd8SNickeau}
692