xref: /plugin/mikioplugin/syntax/core.php (revision ebb7bc5ac16c24c6631f149cafc00314e0ea4d4e)
1<?php
2/**
3 * Mikio Core Syntax Plugin
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     James Collins <james.collins@outlook.com.au>
7 */
8
9if (!defined('DOKU_INC')) die();
10if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
11
12
13class syntax_plugin_mikioplugin_core extends DokuWiki_Syntax_Plugin {
14    public $pattern_entry       = '';
15    public $pattern_exit        = '';
16    public $tag                 = '';
17    public $noEndTag            = false;
18    public $defaults            = array();
19    public $options             = array();
20    public $privateOptions      = false;
21    public $values              = array();
22    public $incClasses          = array('shadow', 'shadow-none', 'shadow-sm', 'shadow-lg', 'w-25', 'w-50', 'w-75', 'w-100', 'w-auto', 'h-25', 'h-50', 'h-75', 'h-100', 'h-auto', 'text-left', 'text-center', 'text-right', 'text-justify', 'text-wrap', 'text-nowrap', 'text-truncate', 'text-break', 'text-lowercase', 'text-uppercase', 'text-capitalize', 'font-weight-bold', 'font-weight-bolder', 'font-weight-normal', 'font-weight-light', 'font-weight-lighter', 'font-italic', 'text-monospace', 'text-reset', 'text-muted', 'text-decoration-none', 'text-primary', 'text-secondary', 'text-success', 'text-danger', 'text-warning', 'text-info', 'text-light'. 'text-dark', 'text-body', 'text-white', 'text-black', 'text-white-50', 'text-black-50', 'bg-primary', 'bg-secondary', 'bg-success', 'bg-danger', 'bg-warning', 'bg-info', 'bg-light', 'bg-dark', 'bg-white', 'bg-transparent', 'border', 'border-top', 'border-right', 'border-bottom', 'border-left', 'border-0', 'border-top-0', 'border-right-0', 'border-bottom-0', 'border-left-0', 'border-primary', 'border-secondary', 'border-success', 'border-danger', 'border-warning', 'border-info', 'border-light', 'border-dark', 'border-white', 'rounded', 'rounded-top', 'rounded-right', 'rounded-bottom', 'rounded-left', 'rounded-circle', 'rounded-pill', 'rounded-0', 'rounded-sm', 'rounded-lg', 'clearfix', 'align-baseline', 'align-top', 'align-middle', 'align-bottom', 'align-text-top', 'align-text-bottom', 'sm-1', 'sm-2', 'sm-3', 'sm-4', 'sm-5', 'sm-6', 'sm-7', 'sm-8', 'sm-9', 'sm-10', 'sm-11', 'sm-12', 'md-1', 'md-2', 'md-3', 'md-4', 'md-5', 'md-6', 'md-7', 'md-8', 'md-9', 'md-10', 'md-11', 'md-12', 'lg-1', 'lg-2', 'lg-3', 'lg-4', 'lg-5', 'lg-6', 'lg-7', 'lg-8', 'lg-9', 'lg-10', 'lg-11', 'lg-12');
23    public $incOptions          = array('width', 'min-width', 'max-width', 'height', 'min-height', 'max-height', 'overflow', 'tooltip', 'tooltip-html', 'tooltop-left', 'tooltip-top', 'tooltip-right', 'tooltip-bottom', 'tooltip-html-top', 'tooltip-html-left', 'tooltip-html-right', 'tooltip-html-bottom');
24
25
26    function __construct() {
27        if(count($this->incClasses) > 0 && !$this->privateOptions) {
28            $this->options = array_merge($this->options, $this->incClasses, $this->incOptions);
29        }
30    }
31
32    public function getType() {
33        return 'formatting';
34    }
35
36
37    public function getAllowedTypes() { return array('formatting', 'substition', 'disabled'); }
38    public function getSort(){ return 32; }
39
40
41    public function connectTo($mode) {
42        if($this->pattern_entry == '' && $this->tag != '') {
43            if($this->noEndTag) {
44                $this->pattern_entry = '<(?:' . strtoupper($this->tag) . '|' . strtolower($this->tag) . ').*?>';
45            } else {
46                $this->pattern_entry = '<(?:' . strtoupper($this->tag) . '|' . strtolower($this->tag) . ').*?>(?=.*?</(?:' . strtoupper($this->tag) . '|' . strtolower($this->tag) . ')>)';
47            }
48        }
49
50        if($this->pattern_entry != '') {
51            if($this->noEndTag) {
52                $this->Lexer->addSpecialPattern($this->pattern_entry, $mode, 'plugin_mikioplugin_'.$this->getPluginComponent());
53            } else {
54                $this->Lexer->addEntryPattern($this->pattern_entry, $mode, 'plugin_mikioplugin_'.$this->getPluginComponent());
55            }
56        }
57    }
58
59
60    public function postConnect() {
61        if(!$this->noEndTag) {
62            if($this->pattern_exit == '' && $this->tag != '') {
63                $this->pattern_exit = '</(?:' . strtoupper($this->tag) . '|' . strtolower($this->tag) . ')>';
64            }
65
66            if($this->pattern_exit != '') {
67                $this->Lexer->addExitPattern($this->pattern_exit, 'plugin_mikioplugin_'.$this->getPluginComponent());
68            }
69        }
70    }
71
72    public function handle($match, $state, $pos, Doku_Handler $handler){
73        switch($state) {
74            case DOKU_LEXER_ENTER:
75            case DOKU_LEXER_SPECIAL:
76                $optionlist = preg_split('/\s(?=([^"]*"[^"]*")*[^"]*$)/', substr($match, strlen($this->tag) + 1, -1));
77
78                $options = array();
79                foreach($optionlist as $item) {
80                    $i = strpos($item, '=');
81                    if($i !== false) {
82                        $value = substr($item, $i + 1);
83
84                        if(substr($value, 0, 1) == '"') $value = substr($value, 1);
85                        if(substr($value, -1) == '"') $value = substr($value, 0, -1);
86
87                        $options[substr($item, 0, $i)] = $value;
88                    } else {
89                        $options[$item] = true;
90                    }
91                }
92
93                $options_clean = $this->cleanOptions($options);
94
95                $this->values = $options_clean;
96
97                return array($state, $options_clean);
98
99            case DOKU_LEXER_UNMATCHED:
100                return array($state, $match);
101
102            case DOKU_LEXER_EXIT:
103                return array($state, '');
104        }
105
106        return array();
107    }
108
109
110    public function cleanOptions($options) {
111        $options_clean = array();
112
113        if(!$this->privateOptions) {
114            foreach($this->options as $item => $value) {
115                if(is_string($value)) {
116                    if(array_key_exists($value, $options)) {
117                        $options_clean[$value] = $options[$value];
118                    } else {
119                        $options_clean[$value] = false;
120                    }
121                } else if(is_array($value)) {
122                    foreach($value as $avalue) {
123                        if(array_key_exists($avalue, $options)) {
124                            $options_clean[$item] = $avalue;
125                        }
126                    }
127                }
128            }
129
130            foreach($this->defaults as $item => $value) {
131                if(array_key_exists($item, $options_clean) == false) {
132                    $options_clean[$item] = $value;
133                }
134            }
135        } else {
136            $options_clean = $options;
137            array_shift($options_clean);
138        }
139
140        return $options_clean;
141    }
142
143
144    public function render_lexer_enter(Doku_Renderer $renderer, $data) {
145
146    }
147
148
149    public function render_lexer_unmatched(Doku_Renderer $renderer, $data) {
150        $renderer->doc .= $renderer->_xmlEntities($data);
151    }
152
153
154    public function render_lexer_exit(Doku_Renderer $renderer, $data) {
155
156    }
157
158
159    public function render_lexer_special(Doku_Renderer $renderer, $data) {
160
161    }
162
163
164    public function render($mode, Doku_Renderer $renderer, $data) {
165        if($mode == 'xhtml'){
166            list($state,$match) = $data;
167
168            switch ($state) {
169                case DOKU_LEXER_ENTER:
170                    $this->render_lexer_enter($renderer, $match);
171                    return true;
172
173                case DOKU_LEXER_UNMATCHED :
174                    $this->render_lexer_unmatched($renderer, $match);
175                    return true;
176
177                case DOKU_LEXER_EXIT :
178                    $this->render_lexer_exit($renderer, $match);
179                    return true;
180
181                case DOKU_LEXER_SPECIAL:
182                    $this->render_lexer_special($renderer, $match);
183                    return true;
184            }
185
186            return true;
187        }
188
189        return false;
190    }
191
192
193    public function buildClassString($options=null, $classes=null, $prefix='') {
194        $s = array();
195
196        if($options != null) {
197            if($classes != null) {
198                foreach($classes as $item) {
199                    if(array_key_exists($item, $options) && $options[$item] !== false) {
200                        $classname = $item;
201
202                        if(is_string($options[$item])) {
203                            $classname = $options[$item];
204                        }
205
206                        if(is_string($prefix)) {
207                            $classname = $prefix . $classname;
208                        } else if(is_array($prefix)) {
209                            foreach($prefix as $pitem => $pvalue) {
210                                if(is_string($pvalue)) {
211                                    if($pvalue == $item) {
212                                        if(is_string($options[$item])) {
213                                            $classname = $pitem . $options[$item];
214                                        } else {
215                                            $classname = $pitem . $item;
216                                        }
217                                    }
218                                }
219
220                                if(is_array($pvalue)) {
221                                    foreach($pvalue as $ppitem) {
222                                        if($ppitem == $item) {
223                                            if(is_string($options[$item])) {
224                                                $classname = $pitem . $options[$item];
225                                            } else {
226                                                $classname = $pitem . $item;
227                                            }
228                                        }
229                                    }
230                                }
231                            }
232                        }
233
234                        $s[] = $classname;
235                    }
236                }
237            }
238
239            foreach($this->incClasses as $item => $value) {
240                if(array_key_exists($value, $options) && $options[$value] == true) {
241                    $pre = substr($value, 0, 3);
242                    if($pre == 'sm-' || $pre == 'md-' || $pre == 'lg-') $value = 'col-' . $value;
243
244                    $s[] = $value;
245                }
246            }
247        }
248
249        $s = ' ' . implode(' ', $s);
250        return $s;
251    }
252
253    public function buildStyleString($options, $ignore=null, $append='') {
254        $s = array();
255
256        if($options != null) {
257            foreach($options as $item => $value) {
258                if($value != false && ($ignore == null || (is_string($ignore) && $ignore != $item) || (is_array($ignore) && in_array($item, $ignore) == false))) {
259                    switch($item) {
260                        case 'width':
261                            $s[] = 'width:' . $value;
262                            break;
263                        case 'height':
264                            $s[] = 'height:' . $value;
265                            break;
266                        case 'min-width':
267                            $s[] = 'min-width:' . $value;
268                            break;
269                        case 'min-height':
270                            $s[] = 'min-height:' . $value;
271                            break;
272                        case 'max-width':
273                            $s[] = 'max-width:' . $value;
274                            break;
275                        case 'max-height':
276                            $s[] = 'max-height:' . $value;
277                            break;
278                        case 'overflow':
279                            $s[] = 'overflow:' . $value;
280                            break;
281                    }
282                }
283            }
284        }
285
286        $s = implode(';', $s) . $append;
287
288        if($s != '') $s = ' style="' . $s . '" ';
289
290        return $s;
291    }
292
293    public function buildTooltipString($options) {
294        $dataPlacement = 'top';
295        $dataHtml = false;
296        $title = '';
297
298        if($options != null) {
299            if(array_key_exists('tooltip-html-top', $options) && $options['tooltip-html-top'] != '') {
300                $title = $options['tooltip-html-top'];
301                $dataPlacement = 'top';
302            }
303
304            if(array_key_exists('tooltip-html-left', $options) && $options['tooltip-html-left'] != '') {
305                $title = $options['tooltip-html-left'];
306                $dataPlacement = 'left';
307            }
308
309            if(array_key_exists('tooltip-html-bottom', $options) && $options['tooltip-html-bottom'] != '') {
310                $title = $options['tooltip-html-bottom'];
311                $dataPlacement = 'bottom';
312            }
313
314            if(array_key_exists('tooltip-html-right', $options) && $options['tooltip-html-right'] != '') {
315                $title = $options['tooltip-html-right'];
316                $dataPlacement = 'right';
317            }
318
319            if(array_key_exists('tooltip-top', $options) && $options['tooltip-top'] != '') {
320                $title = $options['tooltip-top'];
321                $dataPlacement = 'top';
322            }
323
324            if(array_key_exists('tooltip-left', $options) && $options['tooltip-left'] != '') {
325                $title = $options['tooltip-left'];
326                $dataPlacement = 'left';
327            }
328
329            if(array_key_exists('tooltip-bottom', $options) && $options['tooltip-bottom'] != '') {
330                $title = $options['tooltip-bottom'];
331                $dataPlacement = 'bottom';
332            }
333
334            if(array_key_exists('tooltip-right', $options) && $options['tooltip-right'] != '') {
335                $title = $options['tooltip-right'];
336                $dataPlacement = 'right';
337            }
338
339            if(array_key_exists('tooltip-html', $options) && $options['tooltip-html'] != '') {
340                $title = $options['tooltip-html'];
341                $dataPlacement = 'top';
342            }
343
344            if(array_key_exists('tooltip', $options) && $options['tooltip'] != '') {
345                $title = $options['tooltip'];
346                $dataPlacement = 'top';
347            }
348        }
349
350        if($title != '') {
351            return ' data-toggle="tooltip" data-placement="' . $dataPlacement . '" ' . ($dataHtml == true ? 'data-html="true" ' : '') . 'title="' . $title . '" ';
352        }
353
354        return '';
355    }
356
357    public function getMediaFile($str) {
358        $i = strpos($str, '?');
359        if($i !== false) $str = substr($str, 0, $i);
360
361        $str = preg_replace('/[^\da-zA-Z:_.]+/', '', $str);
362
363        return(tpl_getMediaFile(array($str), false));
364    }
365
366
367    public function getLink($str) {
368        $i = strpos($str, '://');
369        if($i !== false) return $str;
370
371        return wl($str);
372    }
373
374
375    public function setAttr(&$attrList, $attr, $data, $newAttrName='', $newAttrVal='') {
376        if(array_key_exists($attr, $data) && $data[$attr] !== false) {
377            $value = $data[$attr];
378
379            if($newAttrName != '') $attr = $newAttrName;
380            if($newAttrVal != '') {
381                $newAttrVal = str_replace('%%VALUE%%', $value, $newAttrVal);
382                if(strpos($newAttrVal, '%%MEDIA%%') !== false) {
383                    $newAttrVal = str_replace('%%MEDIA%%', $this->getMediaFile($value), $newAttrVal);
384                }
385
386                $value = $newAttrVal;
387            }
388
389            $attrList[$attr] = $value;
390        }
391    }
392
393
394    public function listAttr($attrName, $attrs) {
395        $s = '';
396
397        if(count($attrs) > 0) {
398            foreach($attrs as $item => $value) {
399                $s .= $item . ':' . $value . ';';
400            }
401
402            $s = $attrName . '="' . $s . '" ';
403        }
404
405        return $s;
406    }
407
408
409    public function syntaxRender(Doku_Renderer $renderer, $className, $text, $data=null) {
410        $class = new $className;
411
412        if(!is_array($data)) $data = array();
413
414        $data = $class->cleanOptions($data);
415        $class->values = $data;
416
417        if($class->noEndTag) {
418            $class->render_lexer_special($renderer, $data);
419        } else {
420            $class->render_lexer_enter($renderer, $data);
421            $renderer->doc .= $text;
422            $class->render_lexer_exit($renderer, null);
423        }
424    }
425
426    public function getFirstArrayKey($data) {
427        if(!function_exists('array_key_first')) {
428            foreach($data as $key => $unused) {
429                return $key;
430            }
431        }
432
433        return array_key_first($data);
434    }
435}