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