1<?php
2/**
3 * Automatically highlights configured keywords.
4 * Reads the keywords and their colors from a table on a user-defined wiki page.
5 *
6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author  Klaus Keusch <dev@klauskeusch.de>
8 */
9
10if (!defined('DOKU_INC')) die();
11
12class syntax_plugin_autocolor extends DokuWiki_Syntax_Plugin {
13
14    private $colorMap = null;
15
16    // DokuWiki core mispelling
17    public function getType() { return 'substition'; }
18    public function getSort() { return 300; }
19
20    public function connectTo($mode) {
21        $map = $this->getKeywordMap();
22        if (empty($map)) return;
23
24        foreach (array_keys($map) as $word) {
25            $pattern = '\b' . preg_quote($word, '/') . '\b';
26            $this->Lexer->addSpecialPattern($pattern, $mode, 'plugin_autocolor');
27        }
28    }
29
30    public function handle($match, $state, $pos, Doku_Handler $handler) {
31        return array($match);
32    }
33
34    public function render($mode, Doku_Renderer $renderer, $data) {
35        if ($mode !== 'xhtml') return false;
36
37        $word = $data[0];
38        $map = $this->getKeywordMap();
39
40        $color = isset($map[$word]) ? $map[$word] : '';
41
42        if ($color !== '') {
43            $renderer->doc .= '<span style="color: ' . htmlspecialchars($color, ENT_QUOTES, 'UTF-8') . ';">';
44            $renderer->doc .= htmlspecialchars($word, ENT_QUOTES, 'UTF-8');
45            $renderer->doc .= '</span>';
46        } else {
47            $renderer->doc .= htmlspecialchars($word, ENT_QUOTES, 'UTF-8');
48        }
49        return true;
50    }
51
52    /**
53     * Reads the DokuWiki table and creates the keyword mapping.
54     * The table should be defined on the page specified in the plugin configuration.
55     */
56    private function getKeywordMap() {
57        if ($this->colorMap !== null) {
58            return $this->colorMap;
59        }
60
61        $this->colorMap = [];
62        $pageId = $this->getConf('config_page');
63
64        if (!page_exists($pageId)) {
65            // Fallback
66            return [
67                'DokuWiki' => '#0055b3',
68                'Fehler'   => 'red'
69            ];
70        }
71
72        $rawWikiText = rawWiki($pageId);
73        $lines = explode("\n", $rawWikiText);
74
75        foreach ($lines as $line) {
76            $line = trim($line);
77
78            // We ignore empty lines and header lines (those that start with ^)
79            // A valid data line in DokuWiki always starts with | for tables.
80            if ($line === '' || strpos($line, '|') !== 0) {
81                continue;
82            }
83
84            // Split based on |.
85            // Example: "| Keyword1, Keyword2 | #ff0000 |"
86            // Array index 0 is empty (before the first |), index 1 contains keywords, and index 2 contains the color.
87            $cells = explode('|', $line);
88
89            if (count($cells) >= 3) {
90                $keywordsRaw = $cells[1];
91                $color = trim($cells[2]);
92
93                if ($color === '') continue;
94
95                // Split the comma-separated keywords in this table cell
96                $keywordsList = explode(',', $keywordsRaw);
97                foreach ($keywordsList as $keyword) {
98                    $keyword = trim($keyword);
99                    if ($keyword !== '') {
100                        $this->colorMap[$keyword] = $color;
101                    }
102                }
103            }
104        }
105
106        return $this->colorMap;
107    }
108}