xref: /plugin/skillforge/syntax.php (revision 12fa7ce06de4829ce464095e917e18197b9d4bba)
1<?php
2if (!defined('DOKU_INC')) die();
3
4/**
5 * Optional syntax component: renders <frontmatter> and <skillmeta> blocks as
6 * readable page metadata with an optional ZIP download action.
7 */
8class syntax_plugin_skillforge extends DokuWiki_Syntax_Plugin {
9    public function getType() { return 'substition'; }
10    public function getSort() { return 32; }
11    public function connectTo($mode) {
12        $this->Lexer->addSpecialPattern('<frontmatter>.*?</frontmatter>', $mode, 'plugin_skillforge');
13        $this->Lexer->addSpecialPattern('<skillmeta>.*?</skillmeta>', $mode, 'plugin_skillforge');
14    }
15
16    public function handle($match, $state, $pos, Doku_Handler $handler) {
17        if (preg_match('/^<(frontmatter|skillmeta)>(.*?)<\/\1>$/is', $match, $m)) {
18            return array('metadata' => trim($m[2]));
19        }
20        return array('metadata' => '');
21    }
22
23    public function render($mode, Doku_Renderer $renderer, $data) {
24        if ($mode !== 'xhtml') return true;
25
26        $showMetadata = (bool)$this->getConf('show_rendered_metadata');
27        $showDownload = (bool)$this->getConf('show_page_download_button');
28        if (!$showMetadata && !$showDownload) return true;
29
30        $content = '';
31        if ($showMetadata) {
32            $content .= $this->renderMetadata($data['metadata']);
33        }
34        if ($showDownload && auth_isadmin()) {
35            $content .= $this->renderDownloadButton($data['metadata']);
36        }
37        if ($content === '') return true;
38
39        $renderer->doc .= '<div class="skillforge-page-tools">' . $content . '</div>';
40        return true;
41    }
42
43    private function renderMetadata($metadata) {
44        $fields = $this->parseMetadata($metadata);
45        if (!$fields) return '';
46
47        $html = '<section class="skillforge-metadata"><h2>Skill metadata</h2><dl>';
48        foreach ($fields as $name => $value) {
49            $html .= '<dt>' . hsc($name) . '</dt><dd>';
50            if (is_array($value)) {
51                $html .= '<ul>';
52                foreach ($value as $item) {
53                    $html .= '<li>' . hsc($item) . '</li>';
54                }
55                $html .= '</ul>';
56            } else {
57                $html .= hsc($value);
58            }
59            $html .= '</dd>';
60        }
61        return $html . '</dl></section>';
62    }
63
64    private function renderDownloadButton($metadata) {
65        global $ID;
66        $url = wl($ID, array(
67            'do' => 'skillforge_download_current',
68            'sf_page' => $ID,
69            'sectok' => getSecurityToken()
70        ), false, '&');
71        $label = $this->downloadButtonLabel($metadata);
72
73        return '<p class="skillforge-download"><a class="button" href="' . hsc($url) . '">' . hsc($label) . '</a></p>';
74    }
75
76    private function downloadButtonLabel($metadata) {
77        $label = trim((string)$this->getConf('download_button_label'));
78        if ($label === '') $label = 'Download SKILL.md (.zip)';
79
80        $fields = $this->parseMetadata($metadata);
81        $replacements = array(
82            '{name}' => isset($fields['name']) && !is_array($fields['name']) ? $fields['name'] : '',
83            '{title}' => isset($fields['title']) && !is_array($fields['title']) ? $fields['title'] : '',
84            '{description}' => isset($fields['description']) && !is_array($fields['description']) ? $fields['description'] : '',
85            '{output}' => $this->getConf('output_skill_filename') ?: 'SKILL.md',
86        );
87
88        $label = str_replace(array_keys($replacements), array_values($replacements), $label);
89        $label = preg_replace('/\s+/', ' ', trim($label));
90        return $label !== '' ? $label : 'Download SKILL.md (.zip)';
91    }
92
93    private function parseMetadata($metadata) {
94        $fields = array();
95        $current = null;
96        foreach (preg_split('/\R/', (string)$metadata) as $line) {
97            $line = rtrim($line);
98            if ($line === '' || preg_match('/^\s*#/', $line)) continue;
99
100            if ($current !== null && preg_match('/^\s*-\s*(.+)$/', $line, $m)) {
101                if (!isset($fields[$current]) || !is_array($fields[$current])) $fields[$current] = array();
102                $fields[$current][] = trim($m[1], " \t\"'");
103                continue;
104            }
105
106            if (preg_match('/^([A-Za-z0-9_.-]+):\s*(.*)$/', $line, $m)) {
107                $current = $m[1];
108                $value = trim($m[2], " \t\"'");
109                $fields[$current] = ($value === '') ? array() : $value;
110            }
111        }
112        return $fields;
113    }
114}
115