xref: /dokuwiki/lib/plugins/extension/GuiExtension.php (revision f7f57de8479f2faaf7cd989cbe605004194be3a9)
14fd6a1d7SAndreas Gohr<?php
24fd6a1d7SAndreas Gohr
34fd6a1d7SAndreas Gohrnamespace dokuwiki\plugin\extension;
44fd6a1d7SAndreas Gohr
54fd6a1d7SAndreas Gohrclass GuiExtension extends Gui
64fd6a1d7SAndreas Gohr{
77c184cfcSAndreas Gohr    public const THUMB_WIDTH = 120;
87c184cfcSAndreas Gohr    public const THUMB_HEIGHT = 70;
94fd6a1d7SAndreas Gohr
104fd6a1d7SAndreas Gohr
114fd6a1d7SAndreas Gohr    protected Extension $extension;
124fd6a1d7SAndreas Gohr
134fd6a1d7SAndreas Gohr    public function __construct(Extension $extension)
144fd6a1d7SAndreas Gohr    {
154fd6a1d7SAndreas Gohr        parent::__construct();
164fd6a1d7SAndreas Gohr        $this->extension = $extension;
174fd6a1d7SAndreas Gohr    }
184fd6a1d7SAndreas Gohr
194fd6a1d7SAndreas Gohr
204fd6a1d7SAndreas Gohr    public function render()
214fd6a1d7SAndreas Gohr    {
224fd6a1d7SAndreas Gohr
234fd6a1d7SAndreas Gohr        $classes = $this->getClasses();
244fd6a1d7SAndreas Gohr
255732c960SAndreas Gohr        $html = "<section class=\"$classes\" data-ext=\"{$this->extension->getId()}\">";
2620db0ca9SAndreas Gohr
2720db0ca9SAndreas Gohr        $html .= '<div class="screenshot">';
284fd6a1d7SAndreas Gohr        $html .= $this->thumbnail();
29652715ccSAndreas Gohr        $html .= '<span class="id" title="' . hsc($this->extension->getBase()) . '">' .
30652715ccSAndreas Gohr            hsc($this->extension->getBase()) . '</span>';
3100929f2eSAndreas Gohr        $html .= $this->popularity();
3220db0ca9SAndreas Gohr        $html .= '</div>';
3320db0ca9SAndreas Gohr
3420db0ca9SAndreas Gohr        $html .= '<div class="main">';
35981e70caSAndreas Gohr        $html .= $this->main();
3620db0ca9SAndreas Gohr        $html .= '</div>';
3720db0ca9SAndreas Gohr
38981e70caSAndreas Gohr        $html .= '<div class="notices">';
39981e70caSAndreas Gohr        $html .= $this->notices();
40981e70caSAndreas Gohr        $html .= '</div>';
4120db0ca9SAndreas Gohr
4220db0ca9SAndreas Gohr        $html .= '<div class="details">';
434fd6a1d7SAndreas Gohr        $html .= $this->details();
4420db0ca9SAndreas Gohr        $html .= '</div>';
4520db0ca9SAndreas Gohr
46981e70caSAndreas Gohr        $html .= '<div class="actions">';
4700929f2eSAndreas Gohr        // show the available update if there is one
4800929f2eSAndreas Gohr        if ($this->extension->isUpdateAvailable()) {
49*f7f57de8SAndreas Gohr            $html .= ' <div class="available">' . $this->getLang('available_version') . ' ' .
50*f7f57de8SAndreas Gohr                '<span class="version">' . hsc($this->extension->getLastUpdate()) . '</span></div>';
5120db0ca9SAndreas Gohr        }
5220db0ca9SAndreas Gohr
534fd6a1d7SAndreas Gohr        $html .= $this->actions();
5420db0ca9SAndreas Gohr        $html .= '</div>';
554fd6a1d7SAndreas Gohr
564fd6a1d7SAndreas Gohr
574fd6a1d7SAndreas Gohr        $html .= '</section>';
584fd6a1d7SAndreas Gohr
594fd6a1d7SAndreas Gohr        return $html;
604fd6a1d7SAndreas Gohr    }
614fd6a1d7SAndreas Gohr
624fd6a1d7SAndreas Gohr    // region sections
634fd6a1d7SAndreas Gohr
644fd6a1d7SAndreas Gohr    /**
654fd6a1d7SAndreas Gohr     * Get the link and image tag for the screenshot/thumbnail
664fd6a1d7SAndreas Gohr     *
674fd6a1d7SAndreas Gohr     * @return string The HTML code
684fd6a1d7SAndreas Gohr     */
694fd6a1d7SAndreas Gohr    protected function thumbnail()
704fd6a1d7SAndreas Gohr    {
714fd6a1d7SAndreas Gohr        $screen = $this->extension->getScreenshotURL();
724fd6a1d7SAndreas Gohr        $thumb = $this->extension->getThumbnailURL();
734fd6a1d7SAndreas Gohr
744fd6a1d7SAndreas Gohr        $link = [];
754fd6a1d7SAndreas Gohr        $img = [
764fd6a1d7SAndreas Gohr            'width' => self::THUMB_WIDTH,
774fd6a1d7SAndreas Gohr            'height' => self::THUMB_HEIGHT,
78dc192200SAndreas Gohr            'class' => 'shot',
79dc192200SAndreas Gohr            'loading' => 'lazy',
804fd6a1d7SAndreas Gohr            'alt' => '',
814fd6a1d7SAndreas Gohr        ];
824fd6a1d7SAndreas Gohr
834fd6a1d7SAndreas Gohr        if ($screen) {
844fd6a1d7SAndreas Gohr            $link = [
854fd6a1d7SAndreas Gohr                'href' => $screen,
864fd6a1d7SAndreas Gohr                'target' => '_blank',
874fd6a1d7SAndreas Gohr                'class' => 'extension_screenshot',
884fd6a1d7SAndreas Gohr                'title' => sprintf($this->getLang('screenshot'), $this->extension->getDisplayName())
894fd6a1d7SAndreas Gohr            ];
904fd6a1d7SAndreas Gohr
914fd6a1d7SAndreas Gohr            $img['src'] = $thumb;
924fd6a1d7SAndreas Gohr            $img['alt'] = $link['title'];
934fd6a1d7SAndreas Gohr        } elseif ($this->extension->isTemplate()) {
944fd6a1d7SAndreas Gohr            $img['src'] = DOKU_BASE . 'lib/plugins/extension/images/template.png';
954fd6a1d7SAndreas Gohr        } else {
964fd6a1d7SAndreas Gohr            $img['src'] = DOKU_BASE . 'lib/plugins/extension/images/plugin.png';
974fd6a1d7SAndreas Gohr        }
984fd6a1d7SAndreas Gohr
9920db0ca9SAndreas Gohr        $html = '';
1004fd6a1d7SAndreas Gohr        if ($link) $html .= '<a ' . buildAttributes($link) . '>';
1014fd6a1d7SAndreas Gohr        $html .= '<img ' . buildAttributes($img) . ' />';
1024fd6a1d7SAndreas Gohr        if ($link) $html .= '</a>';
1034fd6a1d7SAndreas Gohr
1044fd6a1d7SAndreas Gohr        return $html;
1054fd6a1d7SAndreas Gohr    }
1064fd6a1d7SAndreas Gohr
1074fd6a1d7SAndreas Gohr    /**
1084fd6a1d7SAndreas Gohr     * The main information about the extension
1094fd6a1d7SAndreas Gohr     *
1104fd6a1d7SAndreas Gohr     * @return string
1114fd6a1d7SAndreas Gohr     */
112981e70caSAndreas Gohr    protected function main()
1134fd6a1d7SAndreas Gohr    {
114981e70caSAndreas Gohr        $html = '';
115981e70caSAndreas Gohr        $html .= '<h2>';
116981e70caSAndreas Gohr        $html .= '<div>';
11700929f2eSAndreas Gohr        $html .= sprintf($this->getLang('extensionby'), hsc($this->extension->getDisplayName()), $this->author());
118981e70caSAndreas Gohr        $html .= '</div>';
1194fd6a1d7SAndreas Gohr
120981e70caSAndreas Gohr        $html .= '<div class="version">';
121981e70caSAndreas Gohr        if ($this->extension->isBundled()) {
122981e70caSAndreas Gohr            $html .= hsc('<' . $this->getLang('status_bundled') . '>');
123981e70caSAndreas Gohr        } elseif ($this->extension->getInstalledVersion()) {
124981e70caSAndreas Gohr            $html .= hsc($this->extension->getInstalledVersion());
125981e70caSAndreas Gohr        }
126981e70caSAndreas Gohr        $html .= '</div>';
127981e70caSAndreas Gohr        $html .= '</h2>';
1284fd6a1d7SAndreas Gohr
129981e70caSAndreas Gohr        $html .= '<p>' . hsc($this->extension->getDescription()) . '</p>';
130981e70caSAndreas Gohr        $html .= $this->mainLinks();
1314fd6a1d7SAndreas Gohr
1324fd6a1d7SAndreas Gohr        return $html;
1334fd6a1d7SAndreas Gohr    }
1344fd6a1d7SAndreas Gohr
1354fd6a1d7SAndreas Gohr    /**
1364fd6a1d7SAndreas Gohr     * Display the available notices for the extension
1374fd6a1d7SAndreas Gohr     *
1384fd6a1d7SAndreas Gohr     * @return string
1394fd6a1d7SAndreas Gohr     */
1404fd6a1d7SAndreas Gohr    protected function notices()
1414fd6a1d7SAndreas Gohr    {
1424fd6a1d7SAndreas Gohr        $notices = Notice::list($this->extension);
1434fd6a1d7SAndreas Gohr
144981e70caSAndreas Gohr        $html = '<ul>';
1454fd6a1d7SAndreas Gohr        foreach ($notices as $type => $messages) {
1464fd6a1d7SAndreas Gohr            foreach ($messages as $message) {
1474fd6a1d7SAndreas Gohr                $message = hsc($message);
14880bc92fbSAndreas Gohr                $message = nl2br($message);
1494fd6a1d7SAndreas Gohr                $message = preg_replace('/`([^`]+)`/', '<bdi>$1</bdi>', $message);
150d2d4b908SAndreas Gohr                $message = sprintf(
151d2d4b908SAndreas Gohr                    '<span class="icon">%s</span><span>%s</span>',
152d2d4b908SAndreas Gohr                    inlineSVG(Notice::icon($type)),
153d2d4b908SAndreas Gohr                    $message
154d2d4b908SAndreas Gohr                );
155981e70caSAndreas Gohr                $html .= '<li class="' . $type . '"><div class="li">' . $message . '</div></li>';
1564fd6a1d7SAndreas Gohr            }
1574fd6a1d7SAndreas Gohr        }
158981e70caSAndreas Gohr        $html .= '</ul>';
1594fd6a1d7SAndreas Gohr        return $html;
1604fd6a1d7SAndreas Gohr    }
1614fd6a1d7SAndreas Gohr
1624fd6a1d7SAndreas Gohr    /**
1634fd6a1d7SAndreas Gohr     * Generate the link bar HTML code
1644fd6a1d7SAndreas Gohr     *
1654fd6a1d7SAndreas Gohr     * @return string The HTML code
1664fd6a1d7SAndreas Gohr     */
1674fd6a1d7SAndreas Gohr    public function mainLinks()
1684fd6a1d7SAndreas Gohr    {
1694fd6a1d7SAndreas Gohr        $html = '<div class="linkbar">';
1704fd6a1d7SAndreas Gohr
1714fd6a1d7SAndreas Gohr
1724fd6a1d7SAndreas Gohr        $homepage = $this->extension->getURL();
1734fd6a1d7SAndreas Gohr        if ($homepage) {
1744fd6a1d7SAndreas Gohr            $params = $this->prepareLinkAttributes($homepage, 'homepage');
1754fd6a1d7SAndreas Gohr            $html .= ' <a ' . buildAttributes($params, true) . '>' . $this->getLang('homepage_link') . '</a>';
1764fd6a1d7SAndreas Gohr        }
1774fd6a1d7SAndreas Gohr
1784fd6a1d7SAndreas Gohr        $bugtracker = $this->extension->getBugtrackerURL();
1794fd6a1d7SAndreas Gohr        if ($bugtracker) {
1804fd6a1d7SAndreas Gohr            $params = $this->prepareLinkAttributes($bugtracker, 'bugs');
1814fd6a1d7SAndreas Gohr            $html .= ' <a ' . buildAttributes($params, true) . '>' . $this->getLang('bugs_features') . '</a>';
1824fd6a1d7SAndreas Gohr        }
1834fd6a1d7SAndreas Gohr
1844fd6a1d7SAndreas Gohr        if ($this->extension->getDonationURL()) {
1854fd6a1d7SAndreas Gohr            $params = $this->prepareLinkAttributes($this->extension->getDonationURL(), 'donate');
1864fd6a1d7SAndreas Gohr            $html .= ' <a ' . buildAttributes($params, true) . '>' . $this->getLang('donate_action') . '</a>';
1874fd6a1d7SAndreas Gohr        }
1884fd6a1d7SAndreas Gohr
1894fd6a1d7SAndreas Gohr
1904fd6a1d7SAndreas Gohr        $html .= '</div>';
1914fd6a1d7SAndreas Gohr
1924fd6a1d7SAndreas Gohr        return $html;
1934fd6a1d7SAndreas Gohr    }
1944fd6a1d7SAndreas Gohr
1954fd6a1d7SAndreas Gohr    /**
1964fd6a1d7SAndreas Gohr     * Create the details section
1974fd6a1d7SAndreas Gohr     *
1984fd6a1d7SAndreas Gohr     * @return string
1994fd6a1d7SAndreas Gohr     */
2004fd6a1d7SAndreas Gohr    protected function details()
2014fd6a1d7SAndreas Gohr    {
2024fd6a1d7SAndreas Gohr        $html = '<details>';
203981e70caSAndreas Gohr        $html .= '<summary>' . $this->getLang('details') . '</summary>';
2044fd6a1d7SAndreas Gohr
2054fd6a1d7SAndreas Gohr
2064fd6a1d7SAndreas Gohr        $default = $this->getLang('unknown');
2074fd6a1d7SAndreas Gohr        $list = [];
2084fd6a1d7SAndreas Gohr
2094fd6a1d7SAndreas Gohr        if (!$this->extension->isBundled()) {
2104fd6a1d7SAndreas Gohr            $list['downloadurl'] = $this->shortlink($this->extension->getDownloadURL(), 'download', $default);
2114fd6a1d7SAndreas Gohr            $list['repository'] = $this->shortlink($this->extension->getSourcerepoURL(), 'repo', $default);
2124fd6a1d7SAndreas Gohr        }
2134fd6a1d7SAndreas Gohr
2144fd6a1d7SAndreas Gohr        if ($this->extension->isInstalled()) {
2154fd6a1d7SAndreas Gohr            if ($this->extension->isBundled()) {
2164fd6a1d7SAndreas Gohr                $list['installed_version'] = $this->getLang('status_bundled');
2174fd6a1d7SAndreas Gohr            } else {
2184fd6a1d7SAndreas Gohr                if ($this->extension->getInstalledVersion()) {
2194fd6a1d7SAndreas Gohr                    $list['installed_version'] = hsc($this->extension->getInstalledVersion());
2204fd6a1d7SAndreas Gohr                }
2214fd6a1d7SAndreas Gohr                if (!$this->extension->isBundled()) {
2228fe483c9SAndreas Gohr                    $installDate = $this->extension->getManager()->getInstallDate();
2238fe483c9SAndreas Gohr                    $list['installed'] = $installDate ? dformat($installDate->getTimestamp()) : $default;
2248fe483c9SAndreas Gohr
2254fd6a1d7SAndreas Gohr                    $updateDate = $this->extension->getManager()->getLastUpdate();
2268fe483c9SAndreas Gohr                    $list['install_date'] = $updateDate ? dformat($updateDate->getTimestamp()) : $default;
2274fd6a1d7SAndreas Gohr                }
2284fd6a1d7SAndreas Gohr            }
2294fd6a1d7SAndreas Gohr        }
2304fd6a1d7SAndreas Gohr
2314fd6a1d7SAndreas Gohr        if (!$this->extension->isInstalled() || $this->extension->isUpdateAvailable()) {
2324fd6a1d7SAndreas Gohr            $list['available_version'] = $this->extension->getLastUpdate()
2334fd6a1d7SAndreas Gohr                ? hsc($this->extension->getLastUpdate())
2344fd6a1d7SAndreas Gohr                : $default;
2354fd6a1d7SAndreas Gohr        }
2364fd6a1d7SAndreas Gohr
2374fd6a1d7SAndreas Gohr
2384fd6a1d7SAndreas Gohr        if (!$this->extension->isBundled() && $this->extension->getCompatibleVersions()) {
2397c184cfcSAndreas Gohr            $list['compatible'] = implode(', ', array_map(
2407c184cfcSAndreas Gohr                static fn($date, $version) => '<bdi>' . $version['label'] . ' (' . $date . ')</bdi>',
2414fd6a1d7SAndreas Gohr                array_keys($this->extension->getCompatibleVersions()),
2424fd6a1d7SAndreas Gohr                array_values($this->extension->getCompatibleVersions())
2434fd6a1d7SAndreas Gohr            ));
2444fd6a1d7SAndreas Gohr        }
2454fd6a1d7SAndreas Gohr
2463e63733dSAndreas Gohr        $list['provides'] = implode(', ', array_map('hsc', $this->extension->getComponentTypes()));
2473e63733dSAndreas Gohr
2484fd6a1d7SAndreas Gohr        $tags = $this->extension->getTags();
2494fd6a1d7SAndreas Gohr        if ($tags) {
2507c184cfcSAndreas Gohr            $list['tags'] = implode(', ', array_map(function ($tag) {
2514fd6a1d7SAndreas Gohr                $url = $this->tabURL('search', ['q' => 'tag:' . $tag]);
2524fd6a1d7SAndreas Gohr                return '<bdi><a href="' . $url . '">' . hsc($tag) . '</a></bdi>';
2534fd6a1d7SAndreas Gohr            }, $tags));
2544fd6a1d7SAndreas Gohr        }
2554fd6a1d7SAndreas Gohr
2564fd6a1d7SAndreas Gohr        if ($this->extension->getDependencyList()) {
2574fd6a1d7SAndreas Gohr            $list['depends'] = $this->linkExtensions($this->extension->getDependencyList());
2584fd6a1d7SAndreas Gohr        }
2594fd6a1d7SAndreas Gohr
2604fd6a1d7SAndreas Gohr        if ($this->extension->getSimilarList()) {
2614fd6a1d7SAndreas Gohr            $list['similar'] = $this->linkExtensions($this->extension->getSimilarList());
2624fd6a1d7SAndreas Gohr        }
2634fd6a1d7SAndreas Gohr
2644fd6a1d7SAndreas Gohr        if ($this->extension->getConflictList()) {
2654fd6a1d7SAndreas Gohr            $list['conflicts'] = $this->linkExtensions($this->extension->getConflictList());
2664fd6a1d7SAndreas Gohr        }
2674fd6a1d7SAndreas Gohr
26820db0ca9SAndreas Gohr        $html .= '<dl>';
2694fd6a1d7SAndreas Gohr        foreach ($list as $key => $value) {
2707c995fc8SAndreas Gohr            $html .= '<dt>' . rtrim($this->getLang($key), ':') . '</dt>';
2714fd6a1d7SAndreas Gohr            $html .= '<dd>' . $value . '</dd>';
2724fd6a1d7SAndreas Gohr        }
27320db0ca9SAndreas Gohr        $html .= '</dl>';
2744fd6a1d7SAndreas Gohr
2754fd6a1d7SAndreas Gohr        $html .= '</details>';
2764fd6a1d7SAndreas Gohr        return $html;
2774fd6a1d7SAndreas Gohr    }
2784fd6a1d7SAndreas Gohr
2794fd6a1d7SAndreas Gohr    /**
2804fd6a1d7SAndreas Gohr     * Generate a link to the author of the extension
2814fd6a1d7SAndreas Gohr     *
2824fd6a1d7SAndreas Gohr     * @return string The HTML code of the link
2834fd6a1d7SAndreas Gohr     */
2844fd6a1d7SAndreas Gohr    protected function author()
2854fd6a1d7SAndreas Gohr    {
2864fd6a1d7SAndreas Gohr        if (!$this->extension->getAuthor()) {
2874fd6a1d7SAndreas Gohr            return '<em class="author">' . $this->getLang('unknown_author') . '</em>';
2884fd6a1d7SAndreas Gohr        }
2894fd6a1d7SAndreas Gohr
290981e70caSAndreas Gohr        $names = explode(',', $this->extension->getAuthor());
291981e70caSAndreas Gohr        $names = array_map('trim', $names);
292981e70caSAndreas Gohr        if (count($names) > 2) {
293981e70caSAndreas Gohr            $names = array_slice($names, 0, 2);
294981e70caSAndreas Gohr            $names[] = '…';
295981e70caSAndreas Gohr        }
2967c184cfcSAndreas Gohr        $name = implode(', ', $names);
297981e70caSAndreas Gohr
2984fd6a1d7SAndreas Gohr        $mailid = $this->extension->getEmailID();
2994fd6a1d7SAndreas Gohr        if ($mailid) {
3004fd6a1d7SAndreas Gohr            $url = $this->tabURL('search', ['q' => 'authorid:' . $mailid]);
3014fd6a1d7SAndreas Gohr            $html = '<a href="' . $url . '" class="author" title="' . $this->getLang('author_hint') . '" >' .
3024fd6a1d7SAndreas Gohr                '<img src="//www.gravatar.com/avatar/' . $mailid .
3034fd6a1d7SAndreas Gohr                '?s=60&amp;d=mm" width="20" height="20" alt="" /> ' .
304981e70caSAndreas Gohr                hsc($name) . '</a>';
3054fd6a1d7SAndreas Gohr        } else {
3064fd6a1d7SAndreas Gohr            $html = '<span class="author">' . hsc($this->extension->getAuthor()) . '</span>';
3074fd6a1d7SAndreas Gohr        }
3084fd6a1d7SAndreas Gohr        return '<bdi>' . $html . '</bdi>';
3094fd6a1d7SAndreas Gohr    }
3104fd6a1d7SAndreas Gohr
3114fd6a1d7SAndreas Gohr    /**
3124fd6a1d7SAndreas Gohr     * The popularity bar
3134fd6a1d7SAndreas Gohr     *
3144fd6a1d7SAndreas Gohr     * @return string
3154fd6a1d7SAndreas Gohr     */
3164fd6a1d7SAndreas Gohr    protected function popularity()
3174fd6a1d7SAndreas Gohr    {
3184fd6a1d7SAndreas Gohr        $popularity = $this->extension->getPopularity();
3194fd6a1d7SAndreas Gohr        if (!$popularity) return '';
3204fd6a1d7SAndreas Gohr        if ($this->extension->isBundled()) return '';
3214fd6a1d7SAndreas Gohr
322dc192200SAndreas Gohr        $popimg = '<img src="' . DOKU_BASE . 'lib/plugins/extension/images/fire.svg" alt="��" />';
323dc192200SAndreas Gohr
324981e70caSAndreas Gohr        if ($popularity > 0.25) {
325981e70caSAndreas Gohr            $title = $this->getLang('popularity_high');
326dc192200SAndreas Gohr            $emoji = str_repeat($popimg, 3);
327981e70caSAndreas Gohr        } elseif ($popularity > 0.15) {
328981e70caSAndreas Gohr            $title = $this->getLang('popularity_medium');
329dc192200SAndreas Gohr            $emoji = str_repeat($popimg, 2);
330981e70caSAndreas Gohr        } elseif ($popularity > 0.05) {
331981e70caSAndreas Gohr            $title = $this->getLang('popularity_low');
332dc192200SAndreas Gohr            $emoji = str_repeat($popimg, 1);
333981e70caSAndreas Gohr        } else {
334981e70caSAndreas Gohr            return '';
335981e70caSAndreas Gohr        }
336981e70caSAndreas Gohr        $title .= ' (' . round($popularity * 100) . '%)';
337981e70caSAndreas Gohr
338981e70caSAndreas Gohr        return '<span class="popularity" title="' . $title . '">' . $emoji . '</span>';
3394fd6a1d7SAndreas Gohr    }
3404fd6a1d7SAndreas Gohr
3415732c960SAndreas Gohr    /**
3425732c960SAndreas Gohr     * Generate the action buttons
3435732c960SAndreas Gohr     *
3445732c960SAndreas Gohr     * @return string
3455732c960SAndreas Gohr     */
3464fd6a1d7SAndreas Gohr    protected function actions()
3474fd6a1d7SAndreas Gohr    {
3484fd6a1d7SAndreas Gohr        $html = '';
3494fd6a1d7SAndreas Gohr        $actions = [];
3504fd6a1d7SAndreas Gohr
3515732c960SAndreas Gohr        // check permissions
3524fd6a1d7SAndreas Gohr        try {
3534fd6a1d7SAndreas Gohr            Installer::ensurePermissions($this->extension);
3545732c960SAndreas Gohr        } catch (\Exception $e) {
3555732c960SAndreas Gohr            return '';
3565732c960SAndreas Gohr        }
3574fd6a1d7SAndreas Gohr
3585732c960SAndreas Gohr        // gather available actions
3594fd6a1d7SAndreas Gohr        if ($this->extension->isInstalled()) {
3604fd6a1d7SAndreas Gohr            if (!$this->extension->isProtected()) $actions[] = 'uninstall';
3614fd6a1d7SAndreas Gohr            if ($this->extension->getDownloadURL()) {
3624fd6a1d7SAndreas Gohr                $actions[] = $this->extension->isUpdateAvailable() ? 'update' : 'reinstall';
3634fd6a1d7SAndreas Gohr            }
3647c184cfcSAndreas Gohr            // no enable/disable for templates
3657c184cfcSAndreas Gohr            if (!$this->extension->isProtected() && !$this->extension->isTemplate()) {
3664fd6a1d7SAndreas Gohr                $actions[] = $this->extension->isEnabled() ? 'disable' : 'enable';
3674fd6a1d7SAndreas Gohr            }
3687c184cfcSAndreas Gohr        } elseif ($this->extension->getDownloadURL()) {
3694fd6a1d7SAndreas Gohr            $actions[] = 'install';
3704fd6a1d7SAndreas Gohr        }
3714fd6a1d7SAndreas Gohr
3725732c960SAndreas Gohr        // output the buttons
3734fd6a1d7SAndreas Gohr        foreach ($actions as $action) {
3745732c960SAndreas Gohr            $attr = [
3755732c960SAndreas Gohr                'class' => 'button ' . $action,
3765732c960SAndreas Gohr                'type' => 'submit',
3775732c960SAndreas Gohr                'name' => 'fn[' . $action . '][' . $this->extension->getID() . ']',
3785732c960SAndreas Gohr            ];
3795732c960SAndreas Gohr            $html .= '<button ' . buildAttributes($attr) . '>' . $this->getLang('btn_' . $action) . '</button>';
3804fd6a1d7SAndreas Gohr        }
3814fd6a1d7SAndreas Gohr
3824fd6a1d7SAndreas Gohr        return $html;
3834fd6a1d7SAndreas Gohr    }
3844fd6a1d7SAndreas Gohr
3854fd6a1d7SAndreas Gohr
3864fd6a1d7SAndreas Gohr    // endregion
3874fd6a1d7SAndreas Gohr    // region utility functions
3884fd6a1d7SAndreas Gohr
3894fd6a1d7SAndreas Gohr    /**
3904fd6a1d7SAndreas Gohr     * Create the classes representing the state of the extension
3914fd6a1d7SAndreas Gohr     *
3924fd6a1d7SAndreas Gohr     * @return string
3934fd6a1d7SAndreas Gohr     */
3944fd6a1d7SAndreas Gohr    protected function getClasses()
3954fd6a1d7SAndreas Gohr    {
3964fd6a1d7SAndreas Gohr        $classes = ['extension', $this->extension->getType()];
3974fd6a1d7SAndreas Gohr        if ($this->extension->isInstalled()) $classes[] = 'installed';
3984fd6a1d7SAndreas Gohr        if ($this->extension->isUpdateAvailable()) $classes[] = 'update';
3994fd6a1d7SAndreas Gohr        $classes[] = $this->extension->isEnabled() ? 'enabled' : 'disabled';
4004fd6a1d7SAndreas Gohr        return implode(' ', $classes);
4014fd6a1d7SAndreas Gohr    }
4024fd6a1d7SAndreas Gohr
4034fd6a1d7SAndreas Gohr    /**
4044fd6a1d7SAndreas Gohr     * Create an attributes array for a link
4054fd6a1d7SAndreas Gohr     *
4064fd6a1d7SAndreas Gohr     * Handles interwiki links to dokuwiki.org
4074fd6a1d7SAndreas Gohr     *
4084fd6a1d7SAndreas Gohr     * @param string $url The URL to link to
4094fd6a1d7SAndreas Gohr     * @param string $class Additional classes to add
4104fd6a1d7SAndreas Gohr     * @return array
4114fd6a1d7SAndreas Gohr     */
4124fd6a1d7SAndreas Gohr    protected function prepareLinkAttributes($url, $class)
4134fd6a1d7SAndreas Gohr    {
4144fd6a1d7SAndreas Gohr        global $conf;
4154fd6a1d7SAndreas Gohr
4164fd6a1d7SAndreas Gohr        $attributes = [
4174fd6a1d7SAndreas Gohr            'href' => $url,
4184fd6a1d7SAndreas Gohr            'class' => 'urlextern',
4194fd6a1d7SAndreas Gohr            'target' => $conf['target']['extern'],
4204fd6a1d7SAndreas Gohr            'rel' => 'noopener',
4214fd6a1d7SAndreas Gohr            'title' => $url,
4224fd6a1d7SAndreas Gohr        ];
4234fd6a1d7SAndreas Gohr
4244fd6a1d7SAndreas Gohr        if ($conf['relnofollow']) {
4254fd6a1d7SAndreas Gohr            $attributes['rel'] .= ' ugc nofollow';
4264fd6a1d7SAndreas Gohr        }
4274fd6a1d7SAndreas Gohr
4284fd6a1d7SAndreas Gohr        if (preg_match('/^https?:\/\/(www\.)?dokuwiki\.org\//i', $url)) {
4294fd6a1d7SAndreas Gohr            $attributes['class'] = 'interwiki iw_doku';
4304fd6a1d7SAndreas Gohr            $attributes['target'] = $conf['target']['interwiki'];
4314fd6a1d7SAndreas Gohr            $attributes['rel'] = '';
4324fd6a1d7SAndreas Gohr        }
4334fd6a1d7SAndreas Gohr
4344fd6a1d7SAndreas Gohr        $attributes['class'] .= ' ' . $class;
4354fd6a1d7SAndreas Gohr        return $attributes;
4364fd6a1d7SAndreas Gohr    }
4374fd6a1d7SAndreas Gohr
4384fd6a1d7SAndreas Gohr    /**
4394fd6a1d7SAndreas Gohr     * Create a link from the given URL
4404fd6a1d7SAndreas Gohr     *
4414fd6a1d7SAndreas Gohr     * Shortens the URL for display
4424fd6a1d7SAndreas Gohr     *
4434fd6a1d7SAndreas Gohr     * @param string $url
4444fd6a1d7SAndreas Gohr     * @param string $class Additional classes to add
44500929f2eSAndreas Gohr     * @param string $fallback If URL is empty return this fallback (raw HTML)
4464fd6a1d7SAndreas Gohr     * @return string  HTML link
4474fd6a1d7SAndreas Gohr     */
4484fd6a1d7SAndreas Gohr    protected function shortlink($url, $class, $fallback = '')
4494fd6a1d7SAndreas Gohr    {
45000929f2eSAndreas Gohr        if (!$url) return $fallback;
4514fd6a1d7SAndreas Gohr
4524fd6a1d7SAndreas Gohr        $link = parse_url($url);
4534fd6a1d7SAndreas Gohr        $base = $link['host'];
4544fd6a1d7SAndreas Gohr        if (!empty($link['port'])) $base .= $base . ':' . $link['port'];
4554fd6a1d7SAndreas Gohr        $long = $link['path'];
4564fd6a1d7SAndreas Gohr        if (!empty($link['query'])) $long .= $link['query'];
4574fd6a1d7SAndreas Gohr
4584fd6a1d7SAndreas Gohr        $name = shorten($base, $long, 55);
4594fd6a1d7SAndreas Gohr
4604fd6a1d7SAndreas Gohr        $params = $this->prepareLinkAttributes($url, $class);
4614fd6a1d7SAndreas Gohr        $html = '<a ' . buildAttributes($params, true) . '>' . hsc($name) . '</a>';
4624fd6a1d7SAndreas Gohr        return $html;
4634fd6a1d7SAndreas Gohr    }
4644fd6a1d7SAndreas Gohr
4654fd6a1d7SAndreas Gohr    /**
4664fd6a1d7SAndreas Gohr     * Generate a list of links for extensions
4674fd6a1d7SAndreas Gohr     *
4684fd6a1d7SAndreas Gohr     * Links to the search tab with the extension name
4694fd6a1d7SAndreas Gohr     *
4704fd6a1d7SAndreas Gohr     * @param array $extensions The extension names
4714fd6a1d7SAndreas Gohr     * @return string The HTML code
4724fd6a1d7SAndreas Gohr     */
4734fd6a1d7SAndreas Gohr    public function linkExtensions($extensions)
4744fd6a1d7SAndreas Gohr    {
4754fd6a1d7SAndreas Gohr        $html = '';
4764fd6a1d7SAndreas Gohr        foreach ($extensions as $link) {
4774fd6a1d7SAndreas Gohr            $html .= '<bdi><a href="' .
4784fd6a1d7SAndreas Gohr                $this->tabURL('search', ['q' => 'ext:' . $link]) . '">' .
4794fd6a1d7SAndreas Gohr                hsc($link) . '</a></bdi>, ';
4804fd6a1d7SAndreas Gohr        }
4814fd6a1d7SAndreas Gohr        return rtrim($html, ', ');
4824fd6a1d7SAndreas Gohr    }
4834fd6a1d7SAndreas Gohr
4844fd6a1d7SAndreas Gohr    // endregion
4854fd6a1d7SAndreas Gohr}
486