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