xref: /plugin/button/syntax.php (revision ce70c671b839cef6d2bfaf1e11d59287507dc075)
1ab97758cSPeter Stumm<?php
2ab97758cSPeter Stumm/**
3ab97758cSPeter Stumm * Plugin Button : Add button with image support syntax for links
4ab97758cSPeter Stumm *
5ab97758cSPeter Stumm * To be run with Dokuwiki only
6ab97758cSPeter Stumm
7ab97758cSPeter Stumm *
8ab97758cSPeter Stumm * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
9ab97758cSPeter Stumm * @author     Rémi Peyronnet  <remi+xslt@via.ecp.fr>
10ab97758cSPeter Stumm
11ab97758cSPeter Stumm Full Syntax :
12ab97758cSPeter Stumm     [[{namespace:image|extra css}wiki page|Title of the link]]
13ab97758cSPeter Stumm
14ab97758cSPeter Stumm All fields optional, minimal syntax:
15ab97758cSPeter Stumm    [[{}Simple button]]
16ab97758cSPeter Stumm
17ab97758cSPeter Stumm Configuration :
18ab97758cSPeter Stumm    [[{conf.styles}style|css]]
19ab97758cSPeter Stumm    [[{conf.target}style|target]]
20ab97758cSPeter Stumm
21ab97758cSPeter Stumm 19/05/2013 : Initial release
22ab97758cSPeter Stumm 20/04/2014 : Added target support (feature request from Andrew St Hilaire)
23ab97758cSPeter Stumm 07/06/2014 : Added dokuwiki formatting support in title section (not working in wiki page section) (feature request from Willi Lethert)
24ab97758cSPeter Stumm 30/08/2014 : Added toolbar button (contribution from Xavier Decuyper) and fixed local anchor (bug reported by Andreas Kuzma)
254e3d9946SRémi Peyronnet 06/09/2014 : Refactored to add backlinks support (feature request from Schümmer Hans-Jürgen)
264e3d9946SRémi Peyronnet 28/04/2015 : Refactored global config handling, add internal media link support, add escaping of userinput (contribution from Peter Stumm   https://github.com/lisps/plugin-button)
277e1bed43SRémi Peyronnet 05/08/2015 : Merged lisps default style option and added french translation
2803792051SRémi Peyronnet 12/09/2015 : Fixed PHP error
291c6a0c31SRemi Peyronnet 30/04/2020 : Fixed spaces in image field
30b7a374ddSRemi Peyronnet 04/08/2020 : Quick hack to add compatibility with hogfather
31e20774c3SRemi Peyronnet 07/02/2022 : Added Português do Brasil translation (PR by mac-sousa)
3252d067acSRemi Peyronnet 26/11/2022 : Fixed PHP8.1 warnings
33092313a5SRemi Peyronnet 13/12/2022 : Fixed PHP7 with str_contains polyfill
3467df9406SRemi Peyronnet 05/01/2025 : Added support for interwiki links  (#35)
35ab97758cSPeter Stumm
36929f708eSThisNameIsNotAllowed @author ThisNameIsNotAllowed
37929f708eSThisNameIsNotAllowed 17/11/2016 : Added generation of metadata
38929f708eSThisNameIsNotAllowed 18/11/2016 : Added default target for external links
39e91d7e14SRémi Peyronnet
40e91d7e14SRémi Peyronnet @author lisps
41e91d7e14SRémi Peyronnet 05/03/2017 : Merged lisps move compatibility fixes
421eab5a12SRémi Peyronnet
431eab5a12SRémi Peyronnet @author nerun
441eab5a12SRémi Peyronnet 18/08/2023 : Fixed deprecation warnings in PHP 8+  (#33)
451eab5a12SRémi Peyronnet
46*ce70c671SRémi Peyronnet @author kmlucy
47*ce70c671SRémi Peyronnet 14/07/2026 : Fixed compatibility with DokuWiki Mort (#37)
48*ce70c671SRémi Peyronnet
491eab5a12SRémi Peyronnet Knwon bugs:
5067df9406SRemi Peyronnet - handle / render repartition is not optimal regarding caching, most of the processing should be moved (#14)
51ab97758cSPeter Stumm*/
521eab5a12SRémi Peyronnet
531eab5a12SRémi Peyronnet
54eaddf009SDaniel Dias Rodriguesuse dokuwiki\File\PageResolver;
55eaddf009SDaniel Dias Rodriguesuse dokuwiki\File\MediaResolver;
56ab97758cSPeter Stumm
571eab5a12SRémi Peyronnetif (!defined('DOKU_INC'))
581eab5a12SRémi Peyronnet    die();
591eab5a12SRémi Peyronnetif (!defined('DOKU_PLUGIN'))
601eab5a12SRémi Peyronnet    define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
61b7a374ddSRemi Peyronnet
62b7a374ddSRemi Peyronnet/*  2020-08-04 - This is a quick hack to fix compatibility issue with hogfather (see issue #13) :
63b7a374ddSRemi Peyronnet *  It seems that the handler.php file is no more loaded when rendering cached contents, causing a crash.
64b7a374ddSRemi Peyronnet *  This is due to a bad initial conception of this plugin that does not comply to dokuwiki's guidance of handle / render repartition.
65b7a374ddSRemi Peyronnet *
66b7a374ddSRemi Peyronnet *  FIXME : refactor handle / render repartition ; most of the processing should be moved in the handle section.
67b7a374ddSRemi Peyronnet *  /!\ to be able to do that (and thus, modify the cached content structure) need to find a way to clear the cache while upgrading the plugin...
68*ce70c671SRémi Peyronnet *
69*ce70c671SRémi Peyronnet * 2026-06-14 : This hack is no more needed, you may need to uncomment this line if you are using an old version of dokuwiki (2020-2025)
70*ce70c671SRémi Peyronnet *
71*ce70c671SRémi Peyronnet * require_once(DOKU_INC . 'inc/parser/handler.php');
72b7a374ddSRemi Peyronnet */
73ab97758cSPeter Stumm
74c3e9a88aSRemi Peyronnet// str_contains polyfill for PHP versions before PHP8  (by jnv - #26)
75c3e9a88aSRemi Peyronnetif (!function_exists('str_contains')) {
76c3e9a88aSRemi Peyronnet    function str_contains(string $haystack, string $needle): bool
77c3e9a88aSRemi Peyronnet    {
78c3e9a88aSRemi Peyronnet        return '' === $needle || false !== strpos($haystack, $needle);
79c3e9a88aSRemi Peyronnet    }
80c3e9a88aSRemi Peyronnet}
81c3e9a88aSRemi Peyronnet
821eab5a12SRémi Peyronnetclass syntax_plugin_button extends DokuWiki_Syntax_Plugin
831eab5a12SRémi Peyronnet{
840166612cSunknown
851eab5a12SRémi Peyronnet    function getType()
861eab5a12SRémi Peyronnet    {
871eab5a12SRémi Peyronnet        return 'substition';
881eab5a12SRémi Peyronnet    }
891eab5a12SRémi Peyronnet    function getPType()
901eab5a12SRémi Peyronnet    {
911eab5a12SRémi Peyronnet        return 'normal';
921eab5a12SRémi Peyronnet    }
931eab5a12SRémi Peyronnet    function getSort()
941eab5a12SRémi Peyronnet    {
951eab5a12SRémi Peyronnet        return 25;
961eab5a12SRémi Peyronnet    } // Internal link is 300
971eab5a12SRémi Peyronnet
981eab5a12SRémi Peyronnet    function connectTo($mode)
991eab5a12SRémi Peyronnet    {
1000166612cSunknown        $this->Lexer->addSpecialPattern('\[\[{conf[^}]*}[^\]]*\]\]', $mode, 'plugin_button');
1010166612cSunknown        $this->Lexer->addEntryPattern('\[\[{[^}]*}[^\]\|]*\|?', $mode, 'plugin_button');
1020166612cSunknown        $this->Lexer->addExitPattern(']]', 'plugin_button');
1030166612cSunknown    }
1041eab5a12SRémi Peyronnet    function postConnect()
1051eab5a12SRémi Peyronnet    {
1061eab5a12SRémi Peyronnet    }
1071eab5a12SRémi Peyronnet    function getAllowedTypes()
1081eab5a12SRémi Peyronnet    {
1091eab5a12SRémi Peyronnet        return array('formatting', 'substition');
1101eab5a12SRémi Peyronnet    }
1110166612cSunknown
1120166612cSunknown
1130166612cSunknown
11427360b96Slisps    protected $confStyles;
1150166612cSunknown    protected $styles = array();
1160166612cSunknown    protected $targets = array();
1171eab5a12SRémi Peyronnet    protected function setStyle($name, $value)
1181eab5a12SRémi Peyronnet    {
1190166612cSunknown        global $ID;
1200166612cSunknown        $this->styles[$ID][$name] = $value;
1210166612cSunknown    }
1221eab5a12SRémi Peyronnet    protected function getStyle($name)
1231eab5a12SRémi Peyronnet    {
1240166612cSunknown        global $ID;
12527360b96Slisps        return isset($this->styles[$ID][$name]) ? $this->styles[$ID][$name] : $this->getConfStyles($name);
1260166612cSunknown    }
1271eab5a12SRémi Peyronnet    protected function hasStyle($name)
1281eab5a12SRémi Peyronnet    {
1290166612cSunknown        global $ID;
130f044f88eSRemi Peyronnet        return (array_key_exists($ID, $this->styles) && is_array($this->styles[$ID]) && array_key_exists($name, $this->styles[$ID]))
13127360b96Slisps            || $this->getConfStyles($name) ? true : false;
13227360b96Slisps    }
1331eab5a12SRémi Peyronnet    protected function getConfStyles($name = null)
1341eab5a12SRémi Peyronnet    {
13527360b96Slisps        if ($this->confStyles === null) {
13627360b96Slisps            $this->confStyles = array();
13727360b96Slisps
13827360b96Slisps            $styles = $this->getConf('styles');
1391eab5a12SRémi Peyronnet            if (!$styles)
1401eab5a12SRémi Peyronnet                return;
14127360b96Slisps
14227360b96Slisps            $styles = explode("\n", $styles);
1431eab5a12SRémi Peyronnet            if (!is_array($styles))
1441eab5a12SRémi Peyronnet                return;
14527360b96Slisps
14627360b96Slisps            foreach ($styles as $style) {
14727360b96Slisps                $style = trim($style);
1481eab5a12SRémi Peyronnet                if (!$style)
1491eab5a12SRémi Peyronnet                    continue;
15027360b96Slisps
151f044f88eSRemi Peyronnet                if (str_contains($style, '|')) {
152f044f88eSRemi Peyronnet
15327360b96Slisps                    $style = explode('|', $style, 2);
1541eab5a12SRémi Peyronnet                    if (!is_array($style) || !$style[0] || !$style[1])
1551eab5a12SRémi Peyronnet                        continue;
15627360b96Slisps
15727360b96Slisps                    $this->confStyles[trim($style[0])] = trim($style[1]);
15827360b96Slisps                }
159f044f88eSRemi Peyronnet            }
16027360b96Slisps            //dbg($this->confStyles);
16127360b96Slisps
16227360b96Slisps        }
16327360b96Slisps
16427360b96Slisps        if ($name) {
1651eab5a12SRémi Peyronnet            if (!isset($this->confStyles[$name]))
1661eab5a12SRémi Peyronnet                return false;
16727360b96Slisps
16827360b96Slisps            return $this->confStyles[$name];
16927360b96Slisps        }
17027360b96Slisps        return $this->confStyles;
17127360b96Slisps
1720166612cSunknown    }
1730166612cSunknown
1740166612cSunknown
1751eab5a12SRémi Peyronnet    protected function setTarget($name, $value)
1761eab5a12SRémi Peyronnet    {
1770166612cSunknown        global $ID;
1780166612cSunknown        $this->targets[$ID][$name] = $value;
1790166612cSunknown    }
1801eab5a12SRémi Peyronnet    protected function getTarget($name)
1811eab5a12SRémi Peyronnet    {
1820166612cSunknown        global $ID;
1830166612cSunknown        return $this->targets[$ID][$name];
1840166612cSunknown    }
1851eab5a12SRémi Peyronnet    protected function hasTarget($name)
1861eab5a12SRémi Peyronnet    {
1870166612cSunknown        global $ID;
188f044f88eSRemi Peyronnet        return (array_key_exists($ID, $this->targets) && is_array($this->targets[$ID]) && array_key_exists($name, $this->targets[$ID])) ? true : false;
1890166612cSunknown    }
1900166612cSunknown
1912387a734SAndreas Gohr    function handle($match, $state, $pos, Doku_Handler $handler)
1920166612cSunknown    {
1930166612cSunknown        global $plugin_button_styles;
1940166612cSunknown        global $plugin_button_target;
1950166612cSunknown
1960166612cSunknown        switch ($state) {
1970166612cSunknown            case DOKU_LEXER_SPECIAL:
1980166612cSunknown            case DOKU_LEXER_ENTER:
1990166612cSunknown                $data = '';
2000166612cSunknown                // Button
2011eab5a12SRémi Peyronnet                if (preg_match('/\[\[{ *(?<image>[^}\|]*) *\|?(?<css>[^}]*)}(?<link>[^\]\|]*)\|?(?<title>[^\]]*)/', $match, $matches)) {
2020166612cSunknown                    $data = $matches;
2030166612cSunknown                }
2041eab5a12SRémi Peyronnet                if (is_array($data)) {
2051eab5a12SRémi Peyronnet                    if ($data['image'] == 'conf.styles') {
2060166612cSunknown                        $this->setStyle($data['link'], $data['title']);
2071eab5a12SRémi Peyronnet                    } else if ($data['image'] == 'conf.target') {
2080166612cSunknown                        $this->setTarget($data['link'], $data['title']);
2091eab5a12SRémi Peyronnet                    } else {
2100166612cSunknown                        $data['target'] = "";
2111eab5a12SRémi Peyronnet                        if ($this->hasTarget($data['css'])) {
2120166612cSunknown                            $data['target'] = $this->getTarget($data['css']);
2131eab5a12SRémi Peyronnet                        } else if ($this->hasTarget('default')) {
2140166612cSunknown                            $data['target'] = $this->getTarget('default');
2150166612cSunknown                        }
2160166612cSunknown
2170166612cSunknown
2181eab5a12SRémi Peyronnet                        if ($data['css'] != "" && $this->hasStyle($data['css'])) {
2190166612cSunknown                            $data['css'] = $this->getStyle($data['css']);
2200166612cSunknown                        }
2210166612cSunknown
2221eab5a12SRémi Peyronnet                        if ($this->hasStyle('default') && ($data['css'] != 'default')) {
2230166612cSunknown                            $data['css'] = $this->getStyle('default') . ' ; ' . $data['css'];
2240166612cSunknown                        }
2250166612cSunknown                    }
2260166612cSunknown                }
2270166612cSunknown
2280166612cSunknown                return array($state, $data);
2290166612cSunknown
2301eab5a12SRémi Peyronnet            case DOKU_LEXER_UNMATCHED:
2311eab5a12SRémi Peyronnet                return array($state, $match);
2321eab5a12SRémi Peyronnet            case DOKU_LEXER_EXIT:
2331eab5a12SRémi Peyronnet                return array($state, '');
2340166612cSunknown        }
2350166612cSunknown        return array();
2360166612cSunknown    }
2370166612cSunknown
2382387a734SAndreas Gohr    function render($mode, Doku_Renderer $renderer, $data)
2390166612cSunknown    {
2400166612cSunknown        global $plugin_button_styles;
2410166612cSunknown        global $plugin_button_target;
242929f708eSThisNameIsNotAllowed        global $ID;
243929f708eSThisNameIsNotAllowed        global $conf;
2440166612cSunknown
2450166612cSunknown        if ($mode == 'xhtml') {
2460166612cSunknown            list($state, $match) = $data;
2470166612cSunknown            switch ($state) {
2480166612cSunknown                case DOKU_LEXER_SPECIAL:
2490166612cSunknown                case DOKU_LEXER_ENTER:
2501eab5a12SRémi Peyronnet                    if (is_array($match)) {
2510166612cSunknown                        $image = $match['image'];
2521eab5a12SRémi Peyronnet                        if (($image != "conf.target") && ($image != "conf.styles")) {
2530166612cSunknown                            // Test if internal or external link (from handler.php / internallink)
254fddca096SRemi Peyronnet                            // 2020-07-09 : added special prefix '!' to allow other URI schemes without '//' in it (ex : apt,...)
255fddca096SRemi Peyronnet                            $force_uri_prefix = "!"; // "/" can be confused with url, "!" not working
2561eab5a12SRémi Peyronnet                            if ((substr($match['link'], 0, strlen($force_uri_prefix)) === $force_uri_prefix) || (preg_match('#^mailto:|^([a-z0-9\-\.+]+?)://#i', $match['link']))) {
2570166612cSunknown                                // External
2580166612cSunknown                                $link['url'] = $match['link'];
259fddca096SRemi Peyronnet                                // Strip trailing prefix
2601eab5a12SRémi Peyronnet                                if (substr($link['url'], 0, strlen($force_uri_prefix)) === $force_uri_prefix) {
2611eab5a12SRémi Peyronnet                                    $link['url'] = substr($link['url'], strlen($force_uri_prefix));
2621eab5a12SRémi Peyronnet                                }
263a52b82baSRemi Peyronnet                                // Check if it is an allowed protocol
264a52b82baSRemi Peyronnet                                $link_items = explode(":", $link['url']);
265a52b82baSRemi Peyronnet                                // Adds mailto as it is implicitely allowed wih mail syntax.
266a52b82baSRemi Peyronnet                                if (!in_array($link_items[0], getSchemes() + array('mailto'))) {
267a52b82baSRemi Peyronnet                                    $link['url'] = "Unauthorized URI scheme";
268a52b82baSRemi Peyronnet                                }
2690166612cSunknown                                $link['name'] = $match['title'];
2701eab5a12SRémi Peyronnet                                if ($link['name'] == "")
2711eab5a12SRémi Peyronnet                                    $link['name'] = $match['link'];
2720166612cSunknown                                $link['class'] = 'urlextern';
273929f708eSThisNameIsNotAllowed                                if (strlen($match['target']) == 0) {
274929f708eSThisNameIsNotAllowed                                    $match['target'] = $conf['target']['extern'];
275929f708eSThisNameIsNotAllowed                                }
2761eab5a12SRémi Peyronnet                            } else {
2770166612cSunknown                                // Internal
2780166612cSunknown                                $link = $this->dokuwiki_get_link($renderer, $match['link'], $match['title']);
2790166612cSunknown                            }
2800166612cSunknown                            $target = $match['target'];
2811eab5a12SRémi Peyronnet                            if ($target)
2821eab5a12SRémi Peyronnet                                $target = " target ='" . hsc($target) . "' ";
2830166612cSunknown
2840166612cSunknown                            $link['name'] = str_replace('\\\\', '<br />', $link['name']); //textbreak support
2851eab5a12SRémi Peyronnet                            if ($image != '') {
28627360b96Slisps                                $image = Doku_Handler_Parse_Media("{{" . $image . "}}");
28703792051SRémi Peyronnet                                $image = $this->internalmedia($renderer, $image['src'], null, null, $image['width'], $image['height']);
28803792051SRémi Peyronnet                                $image = "<span class='plugin_button_image'>" . $image['name'] . "</span>";
2890166612cSunknown                            }
2900166612cSunknown                            $text = "<a " . $target . " href='" . $link['url'] . "'><span class='plugin_button' style='" . hsc($match['css']) . "'>$image<span class='plugin_button_text ${link['class']}'>";
2911eab5a12SRémi Peyronnet                            if (substr($match[0], -1) != "|")
2921eab5a12SRémi Peyronnet                                $text .= $link['name'];
2937db634ddSRémi Peyronnet                            $renderer->doc .= $text;
2947db634ddSRémi Peyronnet                            // Update meta data for move
2951eab5a12SRémi Peyronnet                            p_set_metadata(
2961eab5a12SRémi Peyronnet                                $ID,
2971eab5a12SRémi Peyronnet                                array(
298929f708eSThisNameIsNotAllowed                                    'relation' => array(
299929f708eSThisNameIsNotAllowed                                        'references' => array(
300929f708eSThisNameIsNotAllowed                                            $match['link'] => true,
301929f708eSThisNameIsNotAllowed                                        ),
302d731382bSRémi Peyronnet                                        'media' => array(
3037db634ddSRémi Peyronnet                                            $match['image'] => true,
3047db634ddSRémi Peyronnet                                        ),
305929f708eSThisNameIsNotAllowed                                    ),
306929f708eSThisNameIsNotAllowed                                    'plugin_move' => array(
307929f708eSThisNameIsNotAllowed                                        'pages' => array(
308929f708eSThisNameIsNotAllowed                                            $match['link'],
309929f708eSThisNameIsNotAllowed                                        ),
3107db634ddSRémi Peyronnet                                        'medias' => array(
3117db634ddSRémi Peyronnet                                            $match['image'],
3127db634ddSRémi Peyronnet                                        ),
313929f708eSThisNameIsNotAllowed                                    ),
3141eab5a12SRémi Peyronnet                                )
3151eab5a12SRémi Peyronnet                            );
3160166612cSunknown                        }
3170166612cSunknown                    }
3180166612cSunknown                    break;
3190166612cSunknown
3201eab5a12SRémi Peyronnet                case DOKU_LEXER_UNMATCHED:
3211eab5a12SRémi Peyronnet                    $renderer->doc .= $renderer->_xmlEntities($match);
3221eab5a12SRémi Peyronnet                    break;
3231eab5a12SRémi Peyronnet                case DOKU_LEXER_EXIT:
3241eab5a12SRémi Peyronnet                    $renderer->doc .= "</span></span></a>";
3251eab5a12SRémi Peyronnet                    break;
3260166612cSunknown            }
3270166612cSunknown            return true;
3281eab5a12SRémi Peyronnet        } elseif ($mode == 'metadata') {
3290166612cSunknown            list($state, $match) = $data;
3300166612cSunknown            switch ($state) {
3310166612cSunknown                case DOKU_LEXER_SPECIAL:
3320166612cSunknown                case DOKU_LEXER_ENTER:
3331eab5a12SRémi Peyronnet                    if (is_array($match)) {
3340166612cSunknown                        /** @var Doku_Renderer_metadata $renderer */
3350166612cSunknown                        $renderer->internallink($match['link']);
3360166612cSunknown                        // I am assuming that when processing in handle(), you have stored
3370166612cSunknown                        // the link destination in $data[0]
3380166612cSunknown                        return true;
3390166612cSunknown                    }
3400166612cSunknown                    break;
3411eab5a12SRémi Peyronnet                case DOKU_LEXER_UNMATCHED:
3421eab5a12SRémi Peyronnet                    break;
3431eab5a12SRémi Peyronnet                case DOKU_LEXER_EXIT:
3441eab5a12SRémi Peyronnet                    break;
3450166612cSunknown            }
3460166612cSunknown            return true;
3470166612cSunknown        }
3480166612cSunknown        return false;
3490166612cSunknown    }
3500166612cSunknown
35167df9406SRemi Peyronnet    // TODO: the way we get links from dokuwiki should be completely rewritten
35267df9406SRemi Peyronnet    // - target: rework repartition between parser/renderer to match dokuwiki guidelines
35367df9406SRemi Peyronnet    // - try to override $xhtml->_formatLink($link); to avoid the code duplication of the functions below
35467df9406SRemi Peyronnet
3551eab5a12SRémi Peyronnet    function dokuwiki_get_link(&$xhtml, $id, $name = NULL)
3561eab5a12SRémi Peyronnet    {
3570166612cSunknown        global $ID;
35867df9406SRemi Peyronnet
35967df9406SRemi Peyronnet        if (link_isinterwiki($id)) {
36067df9406SRemi Peyronnet            [$wikiName, $wikiUri] = sexplode('>', $id, 2, '');
36167df9406SRemi Peyronnet            $exists = null;
36267df9406SRemi Peyronnet            //$url = $xhtml->_resolveInterWiki($wikiName, $wikiUri, $exists);
36367df9406SRemi Peyronnet            $link = $this->interwikilink($xhtml, $id, $name, $wikiName, $wikiUri, true);
36467df9406SRemi Peyronnet            return $link;
36567df9406SRemi Peyronnet        }
36667df9406SRemi Peyronnet
3679eb108f2SRémi Peyronnet        $resolveid = $id; // To prevent resolve_pageid to change $id value
368eaddf009SDaniel Dias Rodrigues        $resolveid = (new PageResolver($ID))->resolveId($resolveid);
369eaddf009SDaniel Dias Rodrigues        $exists = page_exists($resolveid);
3701e14146cSlisps        if ($exists) {
3711e14146cSlisps            return $this->internallink($xhtml, $id, $name);
3721e14146cSlisps        }
3739eb108f2SRémi Peyronnet        $resolveid = $id;
374eaddf009SDaniel Dias Rodrigues        $resolveid = (new MediaResolver($ID))->resolveId($resolveid);
375eaddf009SDaniel Dias Rodrigues        $exists = media_exists($resolveid);
3760166612cSunknown        if ($exists) {
3770166612cSunknown            return $this->internalmedia($xhtml, $id, $name);
3780166612cSunknown        } else {
3790166612cSunknown            return $this->internallink($xhtml, $id, $name);
3800166612cSunknown        }
3810166612cSunknown    }
3820166612cSunknown
38338605053SRemi Peyronnet    // Copied and adapted from inc/parser/xhtml.php, function internallink (see RPHACK)
384ab97758cSPeter Stumm    // Should use wl instead (from commons), but this won't do the trick for the name
3850166612cSunknown    function internallink(&$xhtml, $id, $name = NULL, $search = NULL, $returnonly = false, $linktype = 'content')
386ab97758cSPeter Stumm    {
387ab97758cSPeter Stumm        global $conf;
388ab97758cSPeter Stumm        global $ID;
389ab97758cSPeter Stumm        global $INFO;
390ab97758cSPeter Stumm
391ab97758cSPeter Stumm
392ab97758cSPeter Stumm        $params = '';
393ab97758cSPeter Stumm        $parts = explode('?', $id, 2);
394ab97758cSPeter Stumm        if (count($parts) === 2) {
395ab97758cSPeter Stumm            $id = $parts[0];
396ab97758cSPeter Stumm            $params = $parts[1];
397ab97758cSPeter Stumm        }
398ab97758cSPeter Stumm
399ab97758cSPeter Stumm        // For empty $id we need to know the current $ID
400ab97758cSPeter Stumm        // We need this check because _simpleTitle needs
401ab97758cSPeter Stumm        // correct $id and resolve_pageid() use cleanID($id)
402ab97758cSPeter Stumm        // (some things could be lost)
403ab97758cSPeter Stumm        if ($id === '') {
404ab97758cSPeter Stumm            $id = $ID;
405ab97758cSPeter Stumm        }
406ab97758cSPeter Stumm
407ab97758cSPeter Stumm        // RPHACK for get_link to work with local links '#id'
408ab97758cSPeter Stumm        if (substr($id, 0, 1) === '#') {
409ab97758cSPeter Stumm            $id = $ID . $id;
410ab97758cSPeter Stumm        }
411ab97758cSPeter Stumm        // -------
412ab97758cSPeter Stumm
413ab97758cSPeter Stumm        // default name is based on $id as given
414ab97758cSPeter Stumm        $default = $xhtml->_simpleTitle($id);
415ab97758cSPeter Stumm
416ab97758cSPeter Stumm        // now first resolve and clean up the $id
417eaddf009SDaniel Dias Rodrigues        $id = (new PageResolver($ID))->resolveId($id);
418eaddf009SDaniel Dias Rodrigues        $exists = page_exists($id);
419ab97758cSPeter Stumm
420ab97758cSPeter Stumm        $name = $xhtml->_getLinkTitle($name, $default, $isImage, $id, $linktype);
421ab97758cSPeter Stumm        if (!$isImage) {
422ab97758cSPeter Stumm            if ($exists) {
423ab97758cSPeter Stumm                $class = 'wikilink1';
424ab97758cSPeter Stumm            } else {
425ab97758cSPeter Stumm                $class = 'wikilink2';
426ab97758cSPeter Stumm                $link['rel'] = 'nofollow';
427ab97758cSPeter Stumm            }
428ab97758cSPeter Stumm        } else {
429ab97758cSPeter Stumm            $class = 'media';
430ab97758cSPeter Stumm        }
431ab97758cSPeter Stumm
432ab97758cSPeter Stumm        //keep hash anchor
43338605053SRemi Peyronnet        $hash = NULL;
4341eab5a12SRémi Peyronnet        if (str_contains($id, '#'))
4351eab5a12SRémi Peyronnet            list($id, $hash) = explode('#', $id, 2);
4361eab5a12SRémi Peyronnet        if (!empty($hash))
4371eab5a12SRémi Peyronnet            $hash = $xhtml->_headerToLink($hash);
438ab97758cSPeter Stumm
439ab97758cSPeter Stumm        //prepare for formating
440ab97758cSPeter Stumm        $link['target'] = $conf['target']['wiki'];
441ab97758cSPeter Stumm        $link['style'] = '';
442ab97758cSPeter Stumm        $link['pre'] = '';
443ab97758cSPeter Stumm        $link['suf'] = '';
444ab97758cSPeter Stumm        // highlight link to current page
445ab97758cSPeter Stumm        if ($id == $INFO['id']) {
446ab97758cSPeter Stumm            $link['pre'] = '<span class="curid">';
447ab97758cSPeter Stumm            $link['suf'] = '</span>';
448ab97758cSPeter Stumm        }
449ab97758cSPeter Stumm        $link['more'] = '';
450ab97758cSPeter Stumm        $link['class'] = $class;
451ab97758cSPeter Stumm        $link['url'] = wl($id, $params);
452ab97758cSPeter Stumm        $link['name'] = $name;
453ab97758cSPeter Stumm        $link['title'] = $id;
454ab97758cSPeter Stumm        //add search string
455ab97758cSPeter Stumm        if ($search) {
456ab97758cSPeter Stumm            ($conf['userewrite']) ? $link['url'] .= '?' : $link['url'] .= '&amp;';
457ab97758cSPeter Stumm            if (is_array($search)) {
458ab97758cSPeter Stumm                $search = array_map('rawurlencode', $search);
459ab97758cSPeter Stumm                $link['url'] .= 's[]=' . join('&amp;s[]=', $search);
460ab97758cSPeter Stumm            } else {
461ab97758cSPeter Stumm                $link['url'] .= 's=' . rawurlencode($search);
462ab97758cSPeter Stumm            }
463ab97758cSPeter Stumm        }
464ab97758cSPeter Stumm
465ab97758cSPeter Stumm        //keep hash
4661eab5a12SRémi Peyronnet        if ($hash)
4671eab5a12SRémi Peyronnet            $link['url'] .= '#' . $hash;
468ab97758cSPeter Stumm
469ab97758cSPeter Stumm        return $link;
470ab97758cSPeter Stumm        //output formatted
471ab97758cSPeter Stumm        //if($returnonly){
472ab97758cSPeter Stumm        //    return $this->_formatLink($link);
473ab97758cSPeter Stumm        //}else{
474ab97758cSPeter Stumm        //    $this->doc .= $this->_formatLink($link);
475ab97758cSPeter Stumm        //}
476ab97758cSPeter Stumm    }
477ab97758cSPeter Stumm
478ab97758cSPeter Stumm
4791eab5a12SRémi Peyronnet    function internalmedia(
4801eab5a12SRémi Peyronnet        &$xhtml,
4811eab5a12SRémi Peyronnet        $src,
4821eab5a12SRémi Peyronnet        $title = NULL,
4831eab5a12SRémi Peyronnet        $align = NULL,
4841eab5a12SRémi Peyronnet        $width = NULL,
4851eab5a12SRémi Peyronnet        $height = NULL,
4861eab5a12SRémi Peyronnet        $cache = NULL,
4871eab5a12SRémi Peyronnet        $linking = NULL
4881eab5a12SRémi Peyronnet    ) {
4890166612cSunknown        global $ID;
490f044f88eSRemi Peyronnet
491f044f88eSRemi Peyronnet        $hash = NULL;
4921eab5a12SRémi Peyronnet        if (str_contains($src, '#'))
4931eab5a12SRémi Peyronnet            list($src, $hash) = explode('#', $src, 2);
494eaddf009SDaniel Dias Rodrigues        $src = (new MediaResolver($ID))->resolveId($src);
495eaddf009SDaniel Dias Rodrigues        $exists = media_exists($src);
496ab97758cSPeter Stumm
4970166612cSunknown        $noLink = false;
4980166612cSunknown        $render = ($linking == 'linkonly') ? false : true;
4990166612cSunknown        $link = $xhtml->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
500ab97758cSPeter Stumm
5010166612cSunknown        list($ext, $mime, $dl) = mimetype($src, false);
5020166612cSunknown        if (substr($mime, 0, 5) == 'image' && $render) {
5030166612cSunknown            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache), ($linking == 'direct'));
5040166612cSunknown        } elseif ($mime == 'application/x-shockwave-flash' && $render) {
5050166612cSunknown            // don't link flash movies
5060166612cSunknown            $noLink = true;
5070166612cSunknown        } else {
5080166612cSunknown            // add file icons
5090166612cSunknown            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext);
5100166612cSunknown            $link['class'] .= ' mediafile mf_' . $class;
5110166612cSunknown            $link['url'] = ml($src, array('id' => $ID, 'cache' => $cache), true);
5121eab5a12SRémi Peyronnet            if ($exists)
5131eab5a12SRémi Peyronnet                $link['title'] .= ' (' . filesize_h(filesize(mediaFN($src))) . ')';
514ab97758cSPeter Stumm        }
515ab97758cSPeter Stumm
5161eab5a12SRémi Peyronnet        if ($hash)
5171eab5a12SRémi Peyronnet            $link['url'] .= '#' . $hash;
518ab97758cSPeter Stumm
5190166612cSunknown        //markup non existing files
5200166612cSunknown        if (!$exists) {
5210166612cSunknown            $link['class'] .= ' wikilink2';
522ab97758cSPeter Stumm        }
523ab97758cSPeter Stumm
5240166612cSunknown        return $link;
5250166612cSunknown        //output formatted
5260166612cSunknown        //if ($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
5270166612cSunknown        //else $this->doc .= $this->_formatLink($link);
528ab97758cSPeter Stumm    }
52967df9406SRemi Peyronnet
53067df9406SRemi Peyronnet    public function interwikilink(&$xhtml, $match, $name, $wikiName, $wikiUri, $returnonly = false)
53167df9406SRemi Peyronnet    {
53267df9406SRemi Peyronnet        global $conf;
53367df9406SRemi Peyronnet
53467df9406SRemi Peyronnet        $link = [];
53567df9406SRemi Peyronnet        $link['target'] = $conf['target']['interwiki'];
53667df9406SRemi Peyronnet        $link['pre'] = '';
53767df9406SRemi Peyronnet        $link['suf'] = '';
53867df9406SRemi Peyronnet        $link['more'] = '';
53967df9406SRemi Peyronnet        $link['name'] = $xhtml->_getLinkTitle($name, $wikiUri, $isImage);
54067df9406SRemi Peyronnet        $link['rel'] = '';
54167df9406SRemi Peyronnet
54267df9406SRemi Peyronnet        //get interwiki URL
54367df9406SRemi Peyronnet        $exists = null;
54467df9406SRemi Peyronnet        $url = $xhtml->_resolveInterWiki($wikiName, $wikiUri, $exists);
54567df9406SRemi Peyronnet
54667df9406SRemi Peyronnet        if (!$isImage) {
54767df9406SRemi Peyronnet            $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $wikiName);
54867df9406SRemi Peyronnet            $link['class'] = "interwiki iw_$class";
54967df9406SRemi Peyronnet        } else {
55067df9406SRemi Peyronnet            $link['class'] = 'media';
55167df9406SRemi Peyronnet        }
55267df9406SRemi Peyronnet
55367df9406SRemi Peyronnet        //do we stay at the same server? Use local target
55467df9406SRemi Peyronnet        if (strpos($url, DOKU_URL) === 0 || strpos($url, DOKU_BASE) === 0) {
55567df9406SRemi Peyronnet            $link['target'] = $conf['target']['wiki'];
55667df9406SRemi Peyronnet        }
55767df9406SRemi Peyronnet        if ($exists !== null && !$isImage) {
55867df9406SRemi Peyronnet            if ($exists) {
55967df9406SRemi Peyronnet                $link['class'] .= ' wikilink1';
56067df9406SRemi Peyronnet            } else {
56167df9406SRemi Peyronnet                $link['class'] .= ' wikilink2';
56267df9406SRemi Peyronnet                $link['rel'] .= ' nofollow';
56367df9406SRemi Peyronnet            }
56467df9406SRemi Peyronnet        }
56567df9406SRemi Peyronnet        if ($conf['target']['interwiki']) $link['rel'] .= ' noopener';
56667df9406SRemi Peyronnet
56767df9406SRemi Peyronnet        $link['url'] = $url;
56867df9406SRemi Peyronnet        $link['title'] = $xhtml->_xmlEntities($link['url']);
56967df9406SRemi Peyronnet
57067df9406SRemi Peyronnet        // return non formatted link
57167df9406SRemi Peyronnet        return $link;
57267df9406SRemi Peyronnet
57367df9406SRemi Peyronnet        /*
57467df9406SRemi Peyronnet        // output formatted
57567df9406SRemi Peyronnet        if ($returnonly) {
57667df9406SRemi Peyronnet            if ($url == '') return $link['name'];
57767df9406SRemi Peyronnet            return $this->_formatLink($link);
57867df9406SRemi Peyronnet        } elseif ($url == '') {
57967df9406SRemi Peyronnet            $this->doc .= $link['name'];
58067df9406SRemi Peyronnet        } else $this->doc .= $this->_formatLink($link);
58167df9406SRemi Peyronnet        */
58267df9406SRemi Peyronnet    }
583ab97758cSPeter Stumm}
5841eab5a12SRémi Peyronnet
585ab97758cSPeter Stumm?>
586