1<?php
2
3use dokuwiki\Extension\SyntaxPlugin;
4use dokuwiki\Parsing\Handler;
5
6/**
7 * BBCode plugin: allows BBCode markup familiar from forum software
8 *
9 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
10 * @author     Esther Brunner <esther@kaffeehaus.ch>
11 * @author     Christopher Smith <chris@jalakai.co.uk>
12 * @author     Luis Machuca Bezzaza <luis.machuca@gulix.cl>
13 */
14class syntax_plugin_bbcode_color extends SyntaxPlugin
15{
16    protected const BROWSERCOLORS =  [
17            'aliceblue' => '#f0f8ff' ,
18            'antiquewhite' => '#faebd7' ,
19            'aqua' => '#00ffff' ,
20            'aquamarine' => '#7fffd4' ,
21            'azure' => '#f0ffff' ,
22            'beige' => '#f5f5dc' ,
23            'bisque' => '#ffe4c4' ,
24            'black' => '#000000' ,
25            'blanchedalmond' => '#ffebcd' ,
26            'blue' => '#0000ff' ,
27            'blueviolet' => '#8a2be2' ,
28            'brown' => '#a52a2a' ,
29            'burlywood' => '#deb887' ,
30            'cadetblue' => '#5f9ea0' ,
31            'chartreuse' => '#7fff00' ,
32            'chocolate' => '#d2691e' ,
33            'coral' => '#ff7f50' ,
34            'cornflowerblue' => '#6495ed' ,
35            'cornsilk' => '#fff8dc' ,
36            'crimson' => '#dc143c' ,
37            'cyan' => '#00ffff' ,
38            'darkblue' => '#00008b' ,
39            'darkcyan' => '#008b8b' ,
40            'darkgoldenrod' => '#b8860b' ,
41            'darkgray' => '#a9a9a9' ,
42            'darkgreen' => '#006400' ,
43            'darkkhaki' => '#bdb76b' ,
44            'darkmagenta' => '#8b008b' ,
45            'darkolivegreen' => '#556b2f' ,
46            'darkorange' => '#ff8c00' ,
47            'darkorchid' => '#9932cc' ,
48            'darkred' => '#8b0000' ,
49            'darksalmon' => '#e9967a' ,
50            'darkseagreen' => '#8fbc8f' ,
51            'darkslateblue' => '#483d8b' ,
52            'darkslategray' => '#2f4f4f' ,
53            'darkturquoise' => '#00ced1' ,
54            'darkviolet' => '#9400d3' ,
55            'deeppink' => '#ff1493' ,
56            'deepskyblue' => '#00bfff' ,
57            'dimgray' => '#696969' ,
58            'dodgerblue' => '#1e90ff' ,
59            'firebrick' => '#b22222' ,
60            'floralwhite' => '#fffaf0' ,
61            'forestgreen' => '#228b22' ,
62            'fuchsia' => '#ff00ff' ,
63            'gainsboro' => '#dcdcdc' ,
64            'ghostwhite' => '#f8f8ff' ,
65            'gold' => '#ffd700' ,
66            'goldenrod' => '#daa520' ,
67            'gray' => '#808080' ,
68            'green' => '#008000' ,
69            'greenyellow' => '#adff2f' ,
70            'honeydew' => '#f0fff0' ,
71            'hotpink' => '#ff69b4' ,
72            'indianred' => '#cd5c5c' ,
73            'indigo' => '#4b0082' ,
74            'ivory' => '#fffff0' ,
75            'khaki' => '#f0e68c' ,
76            'lavender' => '#e6e6fa' ,
77            'lavenderblush' => '#fff0f5' ,
78            'lawngreen' => '#7cfc00' ,
79            'lemonchiffon' => '#fffacd' ,
80            'lightblue' => '#add8e6' ,
81            'lightcoral' => '#f08080' ,
82            'lightcyan' => '#e0ffff' ,
83            'lightgoldenrodyellow' => '#fafad2' ,
84            'lightgrey' => '#d3d3d3' ,
85            'lightgreen' => '#90ee90' ,
86            'lightpink' => '#ffb6c1' ,
87            'lightsalmon' => '#ffa07a' ,
88            'lightseagreen' => '#20b2aa' ,
89            'lightskyblue' => '#87cefa' ,
90            'lightslategray' => '#778899' ,
91            'lightsteelblue' => '#b0c4de' ,
92            'lightyellow' => '#ffffe0' ,
93            'lime' => '#00ff00' ,
94            'limegreen' => '#32cd32' ,
95            'linen' => '#faf0e6' ,
96            'magenta' => '#ff00ff' ,
97            'maroon' => '#800000' ,
98            'mediumaquamarine' => '#66cdaa' ,
99            'mediumblue' => '#0000cd' ,
100            'mediumorchid' => '#ba55d3' ,
101            'mediumpurple' => '#9370d8' ,
102            'mediumseagreen' => '#3cb371' ,
103            'mediumslateblue' => '#7b68ee' ,
104            'mediumspringgreen' => '#00fa9a' ,
105            'mediumturquoise' => '#48d1cc' ,
106            'mediumvioletred' => '#c71585' ,
107            'midnightblue' => '#191970' ,
108            'mintcream' => '#f5fffa' ,
109            'mistyrose' => '#ffe4e1' ,
110            'moccasin' => '#ffe4b5' ,
111            'navajowhite' => '#ffdead' ,
112            'navy' => '#000080' ,
113            'oldlace' => '#fdf5e6' ,
114            'olive' => '#808000' ,
115            'olivedrab' => '#6b8e23' ,
116            'orange' => '#ffa500' ,
117            'orangered' => '#ff4500' ,
118            'orchid' => '#da70d6' ,
119            'palegoldenrod' => '#eee8aa' ,
120            'palegreen' => '#98fb98' ,
121            'paleturquoise' => '#afeeee' ,
122            'palevioletred' => '#d87093' ,
123            'papayawhip' => '#ffefd5' ,
124            'peachpuff' => '#ffdab9' ,
125            'peru' => '#cd853f' ,
126            'pink' => '#ffc0cb' ,
127            'plum' => '#dda0dd' ,
128            'powderblue' => '#b0e0e6' ,
129            'purple' => '#800080' ,
130            'red' => '#ff0000' ,
131            'rosybrown' => '#bc8f8f' ,
132            'royalblue' => '#4169e1' ,
133            'saddlebrown' => '#8b4513' ,
134            'salmon' => '#fa8072' ,
135            'sandybrown' => '#f4a460' ,
136            'seagreen' => '#2e8b57' ,
137            'seashell' => '#fff5ee' ,
138            'sienna' => '#a0522d' ,
139            'silver' => '#c0c0c0' ,
140            'skyblue' => '#87ceeb' ,
141            'slateblue' => '#6a5acd' ,
142            'slategray' => '#708090' ,
143            'snow' => '#fffafa' ,
144            'springgreen' => '#00ff7f' ,
145            'steelblue' => '#4682b4' ,
146            'tan' => '#d2b48c' ,
147            'teal' => '#008080' ,
148            'thistle' => '#d8bfd8' ,
149            'tomato' => '#ff6347' ,
150            'turquoise' => '#40e0d0' ,
151            'violet' => '#ee82ee' ,
152            'wheat' => '#f5deb3' ,
153            'white' => '#ffffff' ,
154            'whitesmoke' => '#f5f5f5' ,
155            'yellow' => '#ffff00' ,
156            'yellowgreen' => '#9acd32' ,
157            ];
158
159    /** @inheritdoc */
160    public function getType()
161    {
162        return 'formatting';
163    }
164    /** @inheritdoc */
165    public function getAllowedTypes()
166    {
167        return ['formatting', 'substition', 'disabled'];
168    }
169    /** @inheritdoc */
170    public function getSort()
171    {
172        return 105;
173    }
174    /** @inheritdoc */
175    public function connectTo($mode)
176    {
177        $this->Lexer->addEntryPattern('\[color=.*?\](?=.*?\x5B/color\x5D)', $mode, 'plugin_bbcode_color');
178    }
179    /** @inheritdoc */
180    public function postConnect()
181    {
182        $this->Lexer->addExitPattern('\[/color\]', 'plugin_bbcode_color');
183    }
184
185    /** @inheritdoc */
186    public function handle($match, $state, $pos, Handler $handler)
187    {
188        switch ($state) {
189            case DOKU_LEXER_ENTER:
190                $match = substr($match, 7, -1);
191                if (preg_match('/".+?"/', $match)) $match = substr($match, 1, -1);
192                return [$state, $match];
193
194            case DOKU_LEXER_UNMATCHED:
195                return [$state, $match];
196
197            case DOKU_LEXER_EXIT:
198                return [$state, ''];
199        }
200        return [];
201    }
202
203    /** @inheritdoc */
204    public function render($format, Doku_Renderer $renderer, $data)
205    {
206        if ($format == 'xhtml') {
207            [$state, $match] = $data;
208            switch ($state) {
209                case DOKU_LEXER_ENTER:
210                    if ($match = $this->isValid($match)) {
211                        $renderer->doc .= '<span style="color:' . $renderer->_xmlEntities($match) . '">';
212                    } else {
213                        $renderer->doc .= '<span>';
214                    }
215                    break;
216
217                case DOKU_LEXER_UNMATCHED:
218                    $renderer->doc .= $renderer->_xmlEntities($match);
219                    break;
220
221                case DOKU_LEXER_EXIT:
222                    $renderer->doc .= '</span>';
223                    break;
224            }
225            return true;
226        }
227        return false;
228    }
229
230    /**
231     * validate color value $c
232     *
233     * this is cut price validation - only to ensure the basic format is correct and there is nothing harmful
234     * three basic formats  "colorname", "#fff[fff]", "rgb(255[%],255[%],255[%])"
235     *
236     * @param string $c color value to validate
237     * @return string valid color value or empty string if invalid
238     */
239    protected function isValid($c)
240    {
241        $c = trim($c);
242
243        $pattern = "/^(
244            ([a-zA-Z]+)|                                #colorname - not verified
245            (\#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}))|        #colorvalue
246            (rgb\(([0-9]{1,3}%?,){2}[0-9]{1,3}%?\))     #rgb triplet
247            )$/xD";
248
249        if (preg_match($pattern, $c)) return $c;
250        if (!empty(self::BROWSERCOLORS[$c])) return self::BROWSERCOLORS[$c];
251        return '';
252    }
253}
254