xref: /plugin/mikioplugin/syntax/core.php (revision 0e73f855dace30f8f9e4565430026d83a555c737)
117e6d639SJames Collins<?php
2*0e73f855Snomadjimbob
317e6d639SJames Collins/**
417e6d639SJames Collins * Mikio Core Syntax Plugin
517e6d639SJames Collins *
67935713eSJames Collins * @link        http://github.com/nomadjimbob/mikioplugin
717e6d639SJames Collins * @license     GPL 2 (http://www.gnu.org/licenses/gpl.html)
817e6d639SJames Collins * @author      James Collins <james.collins@outlook.com.au>
917e6d639SJames Collins */
1017e6d639SJames Collinsif (!defined('DOKU_INC')) die();
1117e6d639SJames Collinsif (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
1217e6d639SJames Collins
137935713eSJames Collinsdefine('MIKIO_LEXER_AUTO', 0);
147935713eSJames Collinsdefine('MIKIO_LEXER_ENTER', 1);
157935713eSJames Collinsdefine('MIKIO_LEXER_EXIT', 2);
167935713eSJames Collinsdefine('MIKIO_LEXER_SPECIAL', 3);
1717e6d639SJames Collins
187935713eSJames Collinsclass syntax_plugin_mikioplugin_core extends DokuWiki_Syntax_Plugin
197935713eSJames Collins{
2017e6d639SJames Collins    public $pattern_entry       = '';
213deaf3a5SJames Collins    public $pattern             = '';
2217e6d639SJames Collins    public $pattern_exit        = '';
2317e6d639SJames Collins    public $tag                 = '';
247935713eSJames Collins    public $hasEndTag           = true;
2517e6d639SJames Collins    public $options             = array();
267935713eSJames Collins
277935713eSJames Collins    protected $tagPrefix          = ''; //'mikio-';
287935713eSJames Collins    protected $classPrefix        = 'mikiop-';
297935713eSJames Collins    protected $elemClass          = 'mikiop';
307935713eSJames Collins
317935713eSJames Collins    private $values              = array();
3217e6d639SJames Collins
3317e6d639SJames Collins
34*0e73f855Snomadjimbob    function __construct()
35*0e73f855Snomadjimbob    {
36*0e73f855Snomadjimbob    }
37*0e73f855Snomadjimbob    public function getType()
38*0e73f855Snomadjimbob    {
39*0e73f855Snomadjimbob        return 'formatting';
40*0e73f855Snomadjimbob    }
41*0e73f855Snomadjimbob    public function getAllowedTypes()
42*0e73f855Snomadjimbob    {
43*0e73f855Snomadjimbob        return array('formatting', 'substition', 'disabled', 'paragraphs');
44*0e73f855Snomadjimbob    }
457935713eSJames Collins    // public function getAllowedTypes() { return array('formatting', 'substition', 'disabled'); }
46*0e73f855Snomadjimbob    public function getSort()
47*0e73f855Snomadjimbob    {
48*0e73f855Snomadjimbob        return 32;
49*0e73f855Snomadjimbob    }
50*0e73f855Snomadjimbob    public function getPType()
51*0e73f855Snomadjimbob    {
52*0e73f855Snomadjimbob        return 'stack';
53*0e73f855Snomadjimbob    }
5417e6d639SJames Collins
5517e6d639SJames Collins
567935713eSJames Collins    public function connectTo($mode)
577935713eSJames Collins    {
5817e6d639SJames Collins        if ($this->pattern_entry == '' && $this->tag != '') {
597935713eSJames Collins            if ($this->hasEndTag) {
607935713eSJames Collins                $this->pattern_entry = '<(?i:' . $this->tagPrefix . $this->tag . ')(?=[ >]).*?>(?=.*?</(?i:' . $this->tagPrefix . $this->tag . ')>)';
6117e6d639SJames Collins            } else {
627935713eSJames Collins                $this->pattern_entry = '<(?i:' . $this->tagPrefix . $this->tag . ').*?>';
6317e6d639SJames Collins            }
6417e6d639SJames Collins        }
6517e6d639SJames Collins
6617e6d639SJames Collins        if ($this->pattern_entry != '') {
677935713eSJames Collins            if ($this->hasEndTag) {
6817e6d639SJames Collins                $this->Lexer->addEntryPattern($this->pattern_entry, $mode, 'plugin_mikioplugin_' . $this->getPluginComponent());
697935713eSJames Collins            } else {
707935713eSJames Collins                $this->Lexer->addSpecialPattern($this->pattern_entry, $mode, 'plugin_mikioplugin_' . $this->getPluginComponent());
717935713eSJames Collins            }
7217e6d639SJames Collins        }
7317e6d639SJames Collins    }
743deaf3a5SJames Collins
7517e6d639SJames Collins
767935713eSJames Collins    public function postConnect()
777935713eSJames Collins    {
787935713eSJames Collins        if ($this->hasEndTag) {
7917e6d639SJames Collins            if ($this->pattern_exit == '' && $this->tag != '') {
807935713eSJames Collins                $this->pattern_exit = '</(?i:' . $this->tagPrefix . $this->tag . ')>';
8117e6d639SJames Collins            }
8217e6d639SJames Collins
8317e6d639SJames Collins            if ($this->pattern_exit != '') {
8417e6d639SJames Collins                $this->Lexer->addExitPattern($this->pattern_exit, 'plugin_mikioplugin_' . $this->getPluginComponent());
8517e6d639SJames Collins            }
8617e6d639SJames Collins        }
8717e6d639SJames Collins    }
8817e6d639SJames Collins
897935713eSJames Collins    public function handle($match, $state, $pos, Doku_Handler $handler)
907935713eSJames Collins    {
9117e6d639SJames Collins        switch ($state) {
9217e6d639SJames Collins            case DOKU_LEXER_ENTER:
9317e6d639SJames Collins            case DOKU_LEXER_SPECIAL:
94c5f7fed6SJames Collins                $match_fix = preg_replace('/\s*=\s*/', '=', trim(substr($match, strlen($this->tagPrefix . $this->tag) + 1, -1)));
95c5f7fed6SJames Collins                $optionlist = preg_split('/\s(?=([^"]*"[^"]*")*[^"]*$)/', $match_fix);
9617e6d639SJames Collins
9717e6d639SJames Collins                $options = array();
9817e6d639SJames Collins                foreach ($optionlist as $item) {
9917e6d639SJames Collins                    $i = strpos($item, '=');
10017e6d639SJames Collins                    if ($i !== false) {
10117e6d639SJames Collins                        $value = substr($item, $i + 1);
10217e6d639SJames Collins
10317e6d639SJames Collins                        if (substr($value, 0, 1) == '"') $value = substr($value, 1);
10417e6d639SJames Collins                        if (substr($value, -1) == '"') $value = substr($value, 0, -1);
10517e6d639SJames Collins
10617e6d639SJames Collins                        $options[substr($item, 0, $i)] = $value;
10717e6d639SJames Collins                    } else {
10817e6d639SJames Collins                        $options[$item] = true;
10917e6d639SJames Collins                    }
11017e6d639SJames Collins                }
11117e6d639SJames Collins
1127935713eSJames Collins                if (count($this->options) > 0) {
11331359b6fSJames Collins                    $options_clean = $this->cleanOptions($options);
1147935713eSJames Collins                } else {
1157935713eSJames Collins                    $options_clean = $options;
1167935713eSJames Collins                }
11731359b6fSJames Collins
11831359b6fSJames Collins                $this->values = $options_clean;
11931359b6fSJames Collins
12031359b6fSJames Collins                return array($state, $options_clean);
12131359b6fSJames Collins
1223deaf3a5SJames Collins            case DOKU_LEXER_MATCHED:
1233deaf3a5SJames Collins                return array($state, $match);
1243deaf3a5SJames Collins
12531359b6fSJames Collins            case DOKU_LEXER_UNMATCHED:
12631359b6fSJames Collins                return array($state, $match);
12731359b6fSJames Collins
12831359b6fSJames Collins            case DOKU_LEXER_EXIT:
129f4aa5cdcSJames Collins                return array($state, $this->values);
13031359b6fSJames Collins        }
13131359b6fSJames Collins
13231359b6fSJames Collins        return array();
13331359b6fSJames Collins    }
13431359b6fSJames Collins
13531359b6fSJames Collins
1367935713eSJames Collins    /*
1377935713eSJames Collins    * clean element options to only supported attributes, setting defaults if required
1387935713eSJames Collins    *
1397935713eSJames Collins    * @param $options   options passed to element
1407935713eSJames Collins    * @return           array of options supported with default set
1417935713eSJames Collins    */
1427935713eSJames Collins    protected function cleanOptions($data, $options = null)
1437935713eSJames Collins    {
1447935713eSJames Collins        $optionsCleaned = array();
14531359b6fSJames Collins
1467935713eSJames Collins        if ($options == null) $options = $this->options;
1477935713eSJames Collins
1487935713eSJames Collins        // Match DokuWiki passed options to syntax options
1497935713eSJames Collins        foreach ($data as $optionKey => $optionValue) {
1507935713eSJames Collins            foreach ($options as $syntaxKey => $syntaxValue) {
1517935713eSJames Collins                if (strcasecmp($optionKey, $syntaxKey) == 0) {
1527935713eSJames Collins                    if (array_key_exists('type', $options[$syntaxKey])) {
1537935713eSJames Collins                        $type = $options[$syntaxKey]['type'];
1547935713eSJames Collins
1557935713eSJames Collins                        switch ($type) {
1567935713eSJames Collins                            case 'boolean':
1577935713eSJames Collins                                $optionsCleaned[$syntaxKey] = filter_var($optionValue, FILTER_VALIDATE_BOOLEAN);
1587935713eSJames Collins                                break;
1597935713eSJames Collins                            case 'number':
1607935713eSJames Collins                                $optionsCleaned[$syntaxKey] = filter_var($optionValue, FILTER_VALIDATE_INT);
1617935713eSJames Collins                                break;
1627935713eSJames Collins                            case 'float':
1637935713eSJames Collins                                $optionsCleaned[$syntaxKey] = filter_var($optionValue, FILTER_VALIDATE_FLOAT);
1647935713eSJames Collins                                break;
1657935713eSJames Collins                            case 'text':
1667935713eSJames Collins                                $optionsCleaned[$syntaxKey] = $optionValue;
1677935713eSJames Collins                                break;
1687935713eSJames Collins                            case 'size':
1697935713eSJames Collins                                $s = strtolower($optionValue);
1707935713eSJames Collins                                $i = '';
1717935713eSJames Collins                                if (substr($s, -3) == 'rem') {
1727935713eSJames Collins                                    $i = substr($s, 0, -3);
1737935713eSJames Collins                                    $s = 'rem';
1747935713eSJames Collins                                } elseif (substr($s, -2) == 'em') {
1757935713eSJames Collins                                    $i = substr($s, 0, -2);
1767935713eSJames Collins                                    $s = 'em';
177*0e73f855Snomadjimbob                                } elseif (substr($s, -2) == 'px') {
1787935713eSJames Collins                                    $i = substr($s, 0, -2);
1797935713eSJames Collins                                    $s = 'px';
180*0e73f855Snomadjimbob                                } elseif (substr($s, -1) == '%') {
1817935713eSJames Collins                                    $i = substr($s, 0, -1);
1827935713eSJames Collins                                    $s = '%';
183*0e73f855Snomadjimbob                                } else {
18418e323fdSJames Collins                                    if ($s != 'auto') {
1857935713eSJames Collins                                        $i = filter_var($s, FILTER_VALIDATE_INT);
1867935713eSJames Collins                                        if ($i == '') $i = '1';
1877935713eSJames Collins                                        $s = 'rem';
1887935713eSJames Collins                                    }
18918e323fdSJames Collins                                }
1907935713eSJames Collins
1917935713eSJames Collins                                $optionsCleaned[$syntaxKey] = $i . $s;
1927935713eSJames Collins                                break;
19318e323fdSJames Collins                            case 'multisize':
19418e323fdSJames Collins                                $val = '';
19518e323fdSJames Collins                                $parts = explode(' ', $optionValue);
19618e323fdSJames Collins                                foreach ($parts as &$part) {
19718e323fdSJames Collins                                    $s = strtolower($part);
19818e323fdSJames Collins                                    $i = '';
19918e323fdSJames Collins                                    if (substr($s, -3) == 'rem') {
20018e323fdSJames Collins                                        $i = substr($s, 0, -3);
20118e323fdSJames Collins                                        $s = 'rem';
20218e323fdSJames Collins                                    } elseif (substr($s, -2) == 'em') {
20318e323fdSJames Collins                                        $i = substr($s, 0, -2);
20418e323fdSJames Collins                                        $s = 'em';
205*0e73f855Snomadjimbob                                    } elseif (substr($s, -2) == 'px') {
20618e323fdSJames Collins                                        $i = substr($s, 0, -2);
20718e323fdSJames Collins                                        $s = 'px';
208*0e73f855Snomadjimbob                                    } elseif (substr($s, -2) == 'fr') {
2092608c53cSJames Collins                                        $i = substr($s, 0, -2);
2102608c53cSJames Collins                                        $s = 'fr';
211*0e73f855Snomadjimbob                                    } elseif (substr($s, -1) == '%') {
21218e323fdSJames Collins                                        $i = substr($s, 0, -1);
21318e323fdSJames Collins                                        $s = '%';
214*0e73f855Snomadjimbob                                    } else {
21518e323fdSJames Collins                                        if ($s != 'auto') {
21618e323fdSJames Collins                                            $i = filter_var($s, FILTER_VALIDATE_INT);
21718e323fdSJames Collins                                            if ($i === '') $i = '1';
21818e323fdSJames Collins                                            if ($i != 0) {
21918e323fdSJames Collins                                                $s = 'rem';
22018e323fdSJames Collins                                            } else {
22118e323fdSJames Collins                                                $s = '';
22218e323fdSJames Collins                                            }
22318e323fdSJames Collins                                        }
22418e323fdSJames Collins                                    }
22518e323fdSJames Collins
22618e323fdSJames Collins                                    $part = $i . $s;
22718e323fdSJames Collins                                }
22818e323fdSJames Collins
22918e323fdSJames Collins                                $optionsCleaned[$syntaxKey] = implode(' ', $parts);
23018e323fdSJames Collins                                break;
2317935713eSJames Collins                            case 'color':
2327935713eSJames Collins                                if (strlen($optionValue) == 3 || strlen($optionValue) == 6) {
2337935713eSJames Collins                                    preg_match('/([[:xdigit:]]{3}){1,2}/', $optionValue, $matches);
2347935713eSJames Collins                                    if (count($matches) > 1) {
2357935713eSJames Collins                                        $optionsCleaned[$syntaxKey] = '#' . $matches[0];
236*0e73f855Snomadjimbob                                    } else {
237*0e73f855Snomadjimbob                                        $optionsCleaned[$syntaxKey] = $optionValue;
2387935713eSJames Collins                                    }
23917e6d639SJames Collins                                } else {
2407935713eSJames Collins                                    $optionsCleaned[$syntaxKey] = $optionValue;
24117e6d639SJames Collins                                }
2427935713eSJames Collins                                break;
2437935713eSJames Collins                            case 'url':
2447935713eSJames Collins                                $optionsCleaned[$syntaxKey] = $this->buildLink($optionValue);
2457935713eSJames Collins                                break;
2467935713eSJames Collins                            case 'media':
2477935713eSJames Collins                                $optionsCleaned[$syntaxKey] = $this->buildMediaLink($optionValue);
2487935713eSJames Collins                                break;
2497935713eSJames Collins                            case 'choice':
2507935713eSJames Collins                                if (array_key_exists('data', $options[$syntaxKey])) {
2517935713eSJames Collins                                    foreach ($options[$syntaxKey]['data'] as $choiceKey => $choiceValue) {
25218e323fdSJames Collins                                        if (strcasecmp($optionValue, $choiceKey) == 0) {
25318e323fdSJames Collins                                            $optionsCleaned[$syntaxKey] = $choiceKey;
25418e323fdSJames Collins                                            break;
25518e323fdSJames Collins                                        }
25618e323fdSJames Collins
2577935713eSJames Collins                                        if (is_array($choiceValue)) {
2587935713eSJames Collins                                            foreach ($choiceValue as $choiceItem) {
2597935713eSJames Collins                                                if (strcasecmp($optionValue, $choiceItem) == 0) {
2607935713eSJames Collins                                                    $optionsCleaned[$syntaxKey] = $choiceKey;
2617935713eSJames Collins                                                    break 2;
26217e6d639SJames Collins                                                }
26317e6d639SJames Collins                                            }
264ebb7bc5aSJames Collins                                        } else {
2657935713eSJames Collins                                            if (strcasecmp($optionValue, $choiceValue) == 0) {
2667935713eSJames Collins                                                $optionsCleaned[$syntaxKey] = $choiceValue;
2677935713eSJames Collins                                                break;
2687935713eSJames Collins                                            }
2697935713eSJames Collins                                        }
2707935713eSJames Collins                                    }
2717935713eSJames Collins                                }
2727935713eSJames Collins                                break;
2737935713eSJames Collins                            case 'set':
2747935713eSJames Collins                                if (array_key_exists('option', $options[$syntaxKey]) && array_key_exists('data', $options[$syntaxKey])) {
2757935713eSJames Collins                                    $optionsCleaned[$options[$syntaxKey]['option']] = $options[$syntaxKey]['data'];
2767935713eSJames Collins                                }
2777935713eSJames Collins                                break;
2787935713eSJames Collins                        }
279ebb7bc5aSJames Collins                    }
28017e6d639SJames Collins
2817935713eSJames Collins                    break;
2827935713eSJames Collins                }
2837935713eSJames Collins            }
2849a439316SJames Collins        }
2859a439316SJames Collins
286ec319cf1SJames Collins
2879a439316SJames Collins        foreach ($data as $optionKey => $optionValue) {
288ec319cf1SJames Collins            if (!array_key_exists($optionKey, $optionsCleaned)) {
289ec319cf1SJames Collins                foreach ($options as $syntaxKey => $syntaxValue) {
290ec319cf1SJames Collins                    if (array_key_exists('type', $options[$syntaxKey])) {
29154ee1cccSJames Collins                        if (array_key_exists('data', $options[$syntaxKey]) && is_array($options[$syntaxKey]['data'])) {
292ec319cf1SJames Collins                            foreach ($options[$syntaxKey]['data'] as $choiceKey => $choiceValue) {
293ec319cf1SJames Collins                                if (is_array($choiceValue)) {
294ec319cf1SJames Collins                                    if (in_array($optionKey, $choiceValue)) {
295ec319cf1SJames Collins                                        $optionsCleaned[$syntaxKey] = $choiceKey;
296ec319cf1SJames Collins                                    }
297ec319cf1SJames Collins                                } else {
298ec319cf1SJames Collins                                    if (strcasecmp($choiceValue, $optionKey) == 0) {
299ec319cf1SJames Collins                                        $optionsCleaned[$syntaxKey] = $choiceValue;
300ec319cf1SJames Collins                                    }
301ec319cf1SJames Collins                                }
302ec319cf1SJames Collins                            }
303ec319cf1SJames Collins                        }
304ec319cf1SJames Collins                    }
3057935713eSJames Collins                }
3067935713eSJames Collins            }
3077935713eSJames Collins        }
30817e6d639SJames Collins
3097935713eSJames Collins        // Add in syntax options that are missing
3107935713eSJames Collins        foreach ($options as $optionKey => $optionValue) {
3117935713eSJames Collins            if (!array_key_exists($optionKey, $optionsCleaned)) {
3127935713eSJames Collins                if (array_key_exists('default', $options[$optionKey])) {
3137935713eSJames Collins                    switch ($options[$optionKey]['type']) {
3147935713eSJames Collins                        case 'boolean':
3157935713eSJames Collins                            $optionsCleaned[$optionKey] = filter_var($options[$optionKey]['default'], FILTER_VALIDATE_BOOLEAN);
3167935713eSJames Collins                            break;
3177935713eSJames Collins                        case 'number':
3187935713eSJames Collins                            $optionsCleaned[$optionKey] = filter_var($options[$optionKey]['default'], FILTER_VALIDATE_INT);
3197935713eSJames Collins                            break;
3207935713eSJames Collins                        default:
3217935713eSJames Collins                            $optionsCleaned[$optionKey] = $options[$optionKey]['default'];
3227935713eSJames Collins                            break;
3237935713eSJames Collins                    }
3247935713eSJames Collins                }
3257935713eSJames Collins            }
32617e6d639SJames Collins        }
32717e6d639SJames Collins
3287935713eSJames Collins        return $optionsCleaned;
32917e6d639SJames Collins    }
33017e6d639SJames Collins
3317935713eSJames Collins    /* Lexer renderers */
332*0e73f855Snomadjimbob    protected function render_lexer_enter(Doku_Renderer $renderer, $data)
333*0e73f855Snomadjimbob    {
334*0e73f855Snomadjimbob    }
335*0e73f855Snomadjimbob    protected function render_lexer_unmatched(Doku_Renderer $renderer, $data)
336*0e73f855Snomadjimbob    {
337*0e73f855Snomadjimbob        $renderer->doc .= $renderer->_xmlEntities($data);
338*0e73f855Snomadjimbob    }
339*0e73f855Snomadjimbob    protected function render_lexer_exit(Doku_Renderer $renderer, $data)
340*0e73f855Snomadjimbob    {
341*0e73f855Snomadjimbob    }
342*0e73f855Snomadjimbob    protected function render_lexer_special(Doku_Renderer $renderer, $data)
343*0e73f855Snomadjimbob    {
344*0e73f855Snomadjimbob    }
345*0e73f855Snomadjimbob    protected function render_lexer_match(Doku_Renderer $renderer, $data)
346*0e73f855Snomadjimbob    {
347*0e73f855Snomadjimbob    }
34817e6d639SJames Collins
3497935713eSJames Collins    /* Renderer */
3507935713eSJames Collins    public function render($mode, Doku_Renderer $renderer, $data)
3517935713eSJames Collins    {
35217e6d639SJames Collins        if ($mode == 'xhtml') {
35317e6d639SJames Collins            list($state, $match) = $data;
35417e6d639SJames Collins
35517e6d639SJames Collins            switch ($state) {
35617e6d639SJames Collins                case DOKU_LEXER_ENTER:
35717e6d639SJames Collins                    $this->render_lexer_enter($renderer, $match);
35817e6d639SJames Collins                    return true;
35917e6d639SJames Collins
36017e6d639SJames Collins                case DOKU_LEXER_UNMATCHED:
36117e6d639SJames Collins                    $this->render_lexer_unmatched($renderer, $match);
36217e6d639SJames Collins                    return true;
36317e6d639SJames Collins
3643deaf3a5SJames Collins                case DOKU_LEXER_MATCHED:
3653deaf3a5SJames Collins                    $this->render_lexer_match($renderer, $match);
3663deaf3a5SJames Collins                    return true;
3673deaf3a5SJames Collins
36817e6d639SJames Collins                case DOKU_LEXER_EXIT:
36917e6d639SJames Collins                    $this->render_lexer_exit($renderer, $match);
37017e6d639SJames Collins                    return true;
37117e6d639SJames Collins
37217e6d639SJames Collins                case DOKU_LEXER_SPECIAL:
37317e6d639SJames Collins                    $this->render_lexer_special($renderer, $match);
37417e6d639SJames Collins                    return true;
37517e6d639SJames Collins            }
37617e6d639SJames Collins
37717e6d639SJames Collins            return true;
37817e6d639SJames Collins        }
37917e6d639SJames Collins
38017e6d639SJames Collins        return false;
38117e6d639SJames Collins    }
38217e6d639SJames Collins
3837935713eSJames Collins    /*
3847935713eSJames Collins    * return a class list with mikiop- prefix
3857935713eSJames Collins    *
3867935713eSJames Collins    * @param $options       options of syntax element. Options with key 'class'=true are automatically added
3877935713eSJames Collins    * @param $classes       classes to build from options as array
3887935713eSJames Collins    * @param $inclAttr      include class="" in the return string
3899d56a2c2SJames Collins    * @param $optionsTemplate   allow a different options template instead of $this->options (for findTags)
3907935713eSJames Collins    * @return               a string of classes from options/classes variable
3917935713eSJames Collins    */
3929d56a2c2SJames Collins    public function buildClass($options = null, $classes = null, $inclAttr = false, $optionsTemplate = null)
3937935713eSJames Collins    {
39417e6d639SJames Collins        $s = array();
39517e6d639SJames Collins
3967935713eSJames Collins        if (is_array($options)) {
3977935713eSJames Collins            if ($classes == null) $classes = array();
3989d56a2c2SJames Collins            if ($optionsTemplate == null) $optionsTemplate = $this->options;
39917e6d639SJames Collins
4009d56a2c2SJames Collins            foreach ($optionsTemplate as $key => $value) {
4017935713eSJames Collins                if (array_key_exists('class', $value) && $value['class'] == TRUE) {
4027935713eSJames Collins                    array_push($classes, $key);
40317e6d639SJames Collins                }
40417e6d639SJames Collins            }
40517e6d639SJames Collins
4067935713eSJames Collins            foreach ($classes as $class) {
4077935713eSJames Collins                if (array_key_exists($class, $options) && $options[$class] !== FALSE && $options[$class] != '') {
4087935713eSJames Collins                    $prefix = $this->classPrefix;
4097935713eSJames Collins
4109d56a2c2SJames Collins                    if (array_key_exists($class, $optionsTemplate) && array_key_exists('prefix', $optionsTemplate[$class])) {
4119d56a2c2SJames Collins                        $prefix .= $optionsTemplate[$class]['prefix'];
41217e6d639SJames Collins                    }
4137935713eSJames Collins
4142f5b9ce6SJames Collins                    if (array_key_exists($class, $optionsTemplate) && array_key_exists('classNoSuffix', $optionsTemplate[$class]) && $optionsTemplate[$class]['classNoSuffix'] == TRUE) {
4152f5b9ce6SJames Collins                        $s[] = $prefix . $class;
4162f5b9ce6SJames Collins                    } else {
4177935713eSJames Collins                        $s[] = $prefix . $class . ($options[$class] !== TRUE ? '-' . $options[$class] : '');
41817e6d639SJames Collins                    }
41917e6d639SJames Collins                }
4202f5b9ce6SJames Collins            }
421a007b54fSJames Collins        }
42217e6d639SJames Collins
4237935713eSJames Collins        $s = implode(' ', $s);
4247935713eSJames Collins        if ($s != '') $s = ' ' . $s;
4258f786230SJames Collins
4267935713eSJames Collins        if ($inclAttr) $s = ' classes="' . $s . '"';
4276cfe6dadSJames Collins
428ad1dae96SJames Collins        return $s;
429ad1dae96SJames Collins    }
43017e6d639SJames Collins
4317935713eSJames Collins
4327935713eSJames Collins
4337935713eSJames Collins
4347935713eSJames Collins    /*
4357935713eSJames Collins    * build style string
4367935713eSJames Collins    *
4377935713eSJames Collins    * @param $list          style list as key => value. Empty values are not included
4387935713eSJames Collins    * @param $inclAttr      include style="" in the return string
4397935713eSJames Collins    * @return               style list string
4407935713eSJames Collins    */
4417935713eSJames Collins    public function buildStyle($list, $inclAttr = false)
4427935713eSJames Collins    {
4437935713eSJames Collins        $s = '';
4447935713eSJames Collins
4457935713eSJames Collins        if (is_array($list) && count($list) > 0) {
4467935713eSJames Collins            foreach ($list as $key => $value) {
4477935713eSJames Collins                if ($value != '') {
4487935713eSJames Collins                    $s .= $key . ':' . $value . ';';
4497935713eSJames Collins                }
4507935713eSJames Collins            }
4517935713eSJames Collins        }
4527935713eSJames Collins
4537935713eSJames Collins        if ($s != '' && $inclAttr) {
4547935713eSJames Collins            $s = ' style="' . $s . '"';
4557935713eSJames Collins        }
4567935713eSJames Collins
4577935713eSJames Collins        return $s;
4587935713eSJames Collins    }
4597935713eSJames Collins
4607935713eSJames Collins
4617935713eSJames Collins    public function buildTooltipString($options)
4627935713eSJames Collins    {
463a401c3b7SJames Collins        $dataPlacement = 'top';
464a401c3b7SJames Collins        $dataHtml = false;
465a401c3b7SJames Collins        $title = '';
466a401c3b7SJames Collins
467a401c3b7SJames Collins        if ($options != null) {
468a401c3b7SJames Collins            if (array_key_exists('tooltip-html-top', $options) && $options['tooltip-html-top'] != '') {
469a401c3b7SJames Collins                $title = $options['tooltip-html-top'];
470a401c3b7SJames Collins                $dataPlacement = 'top';
471a401c3b7SJames Collins            }
472a401c3b7SJames Collins
473a401c3b7SJames Collins            if (array_key_exists('tooltip-html-left', $options) && $options['tooltip-html-left'] != '') {
474a401c3b7SJames Collins                $title = $options['tooltip-html-left'];
475a401c3b7SJames Collins                $dataPlacement = 'left';
476a401c3b7SJames Collins            }
477a401c3b7SJames Collins
478a401c3b7SJames Collins            if (array_key_exists('tooltip-html-bottom', $options) && $options['tooltip-html-bottom'] != '') {
479a401c3b7SJames Collins                $title = $options['tooltip-html-bottom'];
480a401c3b7SJames Collins                $dataPlacement = 'bottom';
481a401c3b7SJames Collins            }
482a401c3b7SJames Collins
483a401c3b7SJames Collins            if (array_key_exists('tooltip-html-right', $options) && $options['tooltip-html-right'] != '') {
484a401c3b7SJames Collins                $title = $options['tooltip-html-right'];
485a401c3b7SJames Collins                $dataPlacement = 'right';
486a401c3b7SJames Collins            }
487a401c3b7SJames Collins
488a401c3b7SJames Collins            if (array_key_exists('tooltip-top', $options) && $options['tooltip-top'] != '') {
489a401c3b7SJames Collins                $title = $options['tooltip-top'];
490a401c3b7SJames Collins                $dataPlacement = 'top';
491a401c3b7SJames Collins            }
492a401c3b7SJames Collins
493a401c3b7SJames Collins            if (array_key_exists('tooltip-left', $options) && $options['tooltip-left'] != '') {
494a401c3b7SJames Collins                $title = $options['tooltip-left'];
495a401c3b7SJames Collins                $dataPlacement = 'left';
496a401c3b7SJames Collins            }
497a401c3b7SJames Collins
498a401c3b7SJames Collins            if (array_key_exists('tooltip-bottom', $options) && $options['tooltip-bottom'] != '') {
499a401c3b7SJames Collins                $title = $options['tooltip-bottom'];
500a401c3b7SJames Collins                $dataPlacement = 'bottom';
501a401c3b7SJames Collins            }
502a401c3b7SJames Collins
503a401c3b7SJames Collins            if (array_key_exists('tooltip-right', $options) && $options['tooltip-right'] != '') {
504a401c3b7SJames Collins                $title = $options['tooltip-right'];
505a401c3b7SJames Collins                $dataPlacement = 'right';
506a401c3b7SJames Collins            }
507a401c3b7SJames Collins
508a401c3b7SJames Collins            if (array_key_exists('tooltip-html', $options) && $options['tooltip-html'] != '') {
509a401c3b7SJames Collins                $title = $options['tooltip-html'];
510a401c3b7SJames Collins                $dataPlacement = 'top';
511a401c3b7SJames Collins            }
512a401c3b7SJames Collins
513a401c3b7SJames Collins            if (array_key_exists('tooltip', $options) && $options['tooltip'] != '') {
514a401c3b7SJames Collins                $title = $options['tooltip'];
515a401c3b7SJames Collins                $dataPlacement = 'top';
516a401c3b7SJames Collins            }
517a401c3b7SJames Collins        }
518a401c3b7SJames Collins
519a401c3b7SJames Collins        if ($title != '') {
520a401c3b7SJames Collins            return ' data-toggle="tooltip" data-placement="' . $dataPlacement . '" ' . ($dataHtml == true ? 'data-html="true" ' : '') . 'title="' . $title . '" ';
521a401c3b7SJames Collins        }
522a401c3b7SJames Collins
523a401c3b7SJames Collins        return '';
524a401c3b7SJames Collins    }
525a401c3b7SJames Collins
5267935713eSJames Collins    /*
5277935713eSJames Collins    * convert the URL to a DokuWiki media link (if required)
5287935713eSJames Collins    *
5297935713eSJames Collins    * @param $url   url to parse
5307935713eSJames Collins    * @return       url string
5317935713eSJames Collins    */
5327935713eSJames Collins    public function buildMediaLink($url)
5337935713eSJames Collins    {
5347935713eSJames Collins        $i = strpos($url, '?');
5357935713eSJames Collins        if ($i !== FALSE) $url = substr($url, 0, $i);
53617e6d639SJames Collins
53766f3b00dSJames Collins        $url = preg_replace('/[^\da-zA-Z:_.-]+/', '', $url);
53817e6d639SJames Collins
5397935713eSJames Collins        return (tpl_getMediaFile(array($url), FALSE));
54017e6d639SJames Collins    }
54117e6d639SJames Collins
54217e6d639SJames Collins
5437935713eSJames Collins    /*
5447935713eSJames Collins    * returns either a url or dokuwiki link
5457935713eSJames Collins    *
5467935713eSJames Collins    * @param    $url    link to build from
5477935713eSJames Collins    * @return           built link
5487935713eSJames Collins    */
5497935713eSJames Collins    public function buildLink($url)
5507935713eSJames Collins    {
5517935713eSJames Collins        $i = strpos($url, '://');
55221a27edbSJames Collins        if ($i !== FALSE || substr($url, 0, 1) == '#') return $url;
553f1a539d8SJames Collins
5547935713eSJames Collins        return wl($url);
555f1a539d8SJames Collins    }
556f1a539d8SJames Collins
5577935713eSJames Collins    /*
5587935713eSJames Collins    * Call syntax renderer of mikio syntax plugin
5597935713eSJames Collins    *
5607935713eSJames Collins    * @param $renderer          DokuWiki renderer object
5617935713eSJames Collins    * @param $className         mikio syntax class to call
5627935713eSJames Collins    * @param $text              unmatched text to pass outside of lexer. Only used when $lexer=MIKIO_LEXER_AUTO
5637935713eSJames Collins    * @param $data              tag options to pass to syntax class. Runs through cleanOptions to validate first
5647935713eSJames Collins    * @param $lexer             which lexer to call
5657935713eSJames Collins    */
5667935713eSJames Collins    public function syntaxRender(Doku_Renderer $renderer, $className, $text, $data = null, $lexer = MIKIO_LEXER_AUTO)
5677935713eSJames Collins    {
5687935713eSJames Collins        $className = 'syntax_plugin_mikioplugin_' . $className;
5697935713eSJames Collins
5707935713eSJames Collins        if (class_exists($className)) {
57117e6d639SJames Collins            $class = new $className;
57217e6d639SJames Collins
57331359b6fSJames Collins            if (!is_array($data)) $data = array();
57431359b6fSJames Collins
57518e323fdSJames Collins
5767935713eSJames Collins            if (count($class->options) > 0) {
57718e323fdSJames Collins                $data = $class->cleanOptions($data, $class->options);
5787935713eSJames Collins            }
57931359b6fSJames Collins
5807935713eSJames Collins            switch ($lexer) {
5817935713eSJames Collins                case MIKIO_LEXER_AUTO:
5827935713eSJames Collins                    if ($class->hasEndTag) {
5837935713eSJames Collins                        if (method_exists($class, 'render_lexer_enter')) $class->render_lexer_enter($renderer, $data);
58417e6d639SJames Collins                        $renderer->doc .= $text;
5857935713eSJames Collins                        if (method_exists($class, 'render_lexer_exit')) $class->render_lexer_exit($renderer, $data);
5867935713eSJames Collins                    } else {
5877935713eSJames Collins                        if (method_exists($class, 'render_lexer_special')) $class->render_lexer_special($renderer, $data);
5887935713eSJames Collins                    }
5897935713eSJames Collins
5907935713eSJames Collins                    break;
5917935713eSJames Collins                case MIKIO_LEXER_ENTER:
5927935713eSJames Collins                    if (method_exists($class, 'render_lexer_enter')) $class->render_lexer_enter($renderer, $data);
5937935713eSJames Collins                    break;
5947935713eSJames Collins                case MIKIO_LEXER_EXIT:
5957935713eSJames Collins                    if (method_exists($class, 'render_lexer_exit')) $class->render_lexer_exit($renderer, $data);
5967935713eSJames Collins                    break;
5977935713eSJames Collins                case MIKIO_LEXER_SPECIAL:
5987935713eSJames Collins                    if (method_exists($class, 'render_lexer_special')) $class->render_lexer_special($renderer, $data);
5997935713eSJames Collins                    break;
6007935713eSJames Collins            }
60117e6d639SJames Collins        }
60217e6d639SJames Collins    }
603ebb7bc5aSJames Collins
6042f5b9ce6SJames Collins
605*0e73f855Snomadjimbob    protected function callMikioTag($className, $data)
606*0e73f855Snomadjimbob    {
60718e323fdSJames Collins        // $className = 'syntax_plugin_mikioplugin_'.$className;
6082f5b9ce6SJames Collins
6092f5b9ce6SJames Collins
61018e323fdSJames Collins        // if(class_exists($className)) {
61118e323fdSJames Collins        //$class = new $className;
61218e323fdSJames Collins        if (!plugin_isdisabled('mikioplugin')) {
61318e323fdSJames Collins            $class = plugin_load('syntax', 'mikioplugin_' . $className);
61418e323fdSJames Collins            // echo '^^'.$className.'^^';
61518e323fdSJames Collins
61618e323fdSJames Collins
61718e323fdSJames Collins            if (method_exists($class, 'mikioCall')) return $class->mikioCall($data);
6182f5b9ce6SJames Collins        }
6192f5b9ce6SJames Collins
62018e323fdSJames Collins        // }
62118e323fdSJames Collins
6222f5b9ce6SJames Collins        return '';
6232f5b9ce6SJames Collins    }
6242f5b9ce6SJames Collins
6252f5b9ce6SJames Collins
626*0e73f855Snomadjimbob    protected function callMikioOptionDefault($className, $option)
627*0e73f855Snomadjimbob    {
628f003e4a8SJames Collins        $className = 'syntax_plugin_mikioplugin_' . $className;
629f003e4a8SJames Collins
630f003e4a8SJames Collins        if (class_exists($className)) {
631f003e4a8SJames Collins            $class = new $className;
632f003e4a8SJames Collins
633f003e4a8SJames Collins            if (array_key_exists($option, $class->options) && array_key_exists('default', $class->options[$option])) {
634f003e4a8SJames Collins                return $class->options[$option]['default'];
635f003e4a8SJames Collins            }
636f003e4a8SJames Collins        }
637f003e4a8SJames Collins
638f003e4a8SJames Collins        return '';
639f003e4a8SJames Collins    }
640f003e4a8SJames Collins
641f003e4a8SJames Collins
642*0e73f855Snomadjimbob    protected function buildTooltip($text)
643*0e73f855Snomadjimbob    {
6442f5b9ce6SJames Collins        if ($text != '') {
6452f5b9ce6SJames Collins            return ' data-tooltip="' . $text . '"';
6462f5b9ce6SJames Collins        }
6472f5b9ce6SJames Collins
6482f5b9ce6SJames Collins        return '';
6492f5b9ce6SJames Collins    }
6502f5b9ce6SJames Collins
6517935713eSJames Collins    /*
6527935713eSJames Collins    * Create array with passed elements and include them if their values are not empty
6537935713eSJames Collins    *
6547935713eSJames Collins    * @param ...        array items
6557935713eSJames Collins    */
656*0e73f855Snomadjimbob    protected function arrayRemoveEmpties($items)
657*0e73f855Snomadjimbob    {
6587935713eSJames Collins        $result = array();
6597935713eSJames Collins
6607935713eSJames Collins        foreach ($items as $key => $value) {
6617935713eSJames Collins            if ($value != '') {
6627935713eSJames Collins                $result[$key] = $value;
6637935713eSJames Collins            }
6647935713eSJames Collins        }
6657935713eSJames Collins
6667935713eSJames Collins        return $result;
6677935713eSJames Collins    }
6687935713eSJames Collins
6697935713eSJames Collins    public function getFirstArrayKey($data)
6707935713eSJames Collins    {
671ebb7bc5aSJames Collins        if (!function_exists('array_key_first')) {
672ebb7bc5aSJames Collins            foreach ($data as $key => $unused) {
673ebb7bc5aSJames Collins                return $key;
674ebb7bc5aSJames Collins            }
675ebb7bc5aSJames Collins        }
676ebb7bc5aSJames Collins
677ebb7bc5aSJames Collins        return array_key_first($data);
678ebb7bc5aSJames Collins    }
6797935713eSJames Collins
6807935713eSJames Collins
6817935713eSJames Collins    /*
6827935713eSJames Collins    * add common options to options
6837935713eSJames Collins    *
6847935713eSJames Collins    * @param $typelist      common option to add
6857935713eSJames Collins    * @param $options   save in options
6867935713eSJames Collins    */
687*0e73f855Snomadjimbob    public function addCommonOptions($typelist)
688*0e73f855Snomadjimbob    {
6897935713eSJames Collins        $types = explode(' ', $typelist);
6907935713eSJames Collins        foreach ($types as $type) {
6917935713eSJames Collins            if (strcasecmp($type, 'shadow') == 0) {
692*0e73f855Snomadjimbob                $this->options['shadow'] =          array(
693*0e73f855Snomadjimbob                    'type'     => 'choice',
6947935713eSJames Collins                    'data'     => array('large' => array('shadow-large', 'shadow-lg'), 'small' => array('shadow-small', 'shadow-sm'), true),
6957935713eSJames Collins                    'default'  => '',
696*0e73f855Snomadjimbob                    'class'    => true
697*0e73f855Snomadjimbob                );
6987935713eSJames Collins            }
6997935713eSJames Collins
7007935713eSJames Collins            if (strcasecmp($type, 'width') == 0) {
701*0e73f855Snomadjimbob                $this->options['width'] =           array(
702*0e73f855Snomadjimbob                    'type'     => 'size',
703*0e73f855Snomadjimbob                    'default'  => ''
704*0e73f855Snomadjimbob                );
7057935713eSJames Collins            }
7067935713eSJames Collins
7077935713eSJames Collins            if (strcasecmp($type, 'height') == 0) {
708*0e73f855Snomadjimbob                $this->options['height'] =          array(
709*0e73f855Snomadjimbob                    'type'     => 'size',
710*0e73f855Snomadjimbob                    'default'  => ''
711*0e73f855Snomadjimbob                );
7127935713eSJames Collins            }
7137935713eSJames Collins
71418e323fdSJames Collins            if (strcasecmp($type, 'text-color') == 0) {
715*0e73f855Snomadjimbob                $this->options['text-color'] =          array(
716*0e73f855Snomadjimbob                    'type'      => 'color',
717*0e73f855Snomadjimbob                    'default'  => ''
718*0e73f855Snomadjimbob                );
71918e323fdSJames Collins            }
72018e323fdSJames Collins
7217935713eSJames Collins            if (strcasecmp($type, 'type') == 0) {
722*0e73f855Snomadjimbob                $this->options['type'] =              array(
723*0e73f855Snomadjimbob                    'type'     => 'text',
724e84ad5e7SJames Collins                    'data'     => array('primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark', 'outline-primary', 'outline-secondary', 'outline-success', 'outline-danger', 'outline-warning', 'outline-info', 'outline-light', 'outline-dark'),
7257935713eSJames Collins                    'default'  => '',
726*0e73f855Snomadjimbob                    'class'    => true
727*0e73f855Snomadjimbob                );
7287935713eSJames Collins            }
7297935713eSJames Collins
7307935713eSJames Collins            if (strcasecmp($type, 'text-align') == 0) {
731*0e73f855Snomadjimbob                $this->options['text-align'] =      array(
732*0e73f855Snomadjimbob                    'type'     => 'choice',
7337935713eSJames Collins                    'data'     => array('left' => array('text-left'), 'center' => array('text-center'), 'right' => array('text-right')),
7347935713eSJames Collins                    'default'  => '',
735*0e73f855Snomadjimbob                    'class'    => true
736*0e73f855Snomadjimbob                );
7377935713eSJames Collins            }
7387935713eSJames Collins
7397935713eSJames Collins            if (strcasecmp($type, 'align') == 0) {
740*0e73f855Snomadjimbob                $this->options['align'] =           array(
741*0e73f855Snomadjimbob                    'type'     => 'choice',
7427935713eSJames Collins                    'data'     => array('left' => array('align-left'), 'center' => array('align-center'), 'right' => array('align-right')),
7437935713eSJames Collins                    'default'  => '',
744*0e73f855Snomadjimbob                    'class'    => true
745*0e73f855Snomadjimbob                );
7467935713eSJames Collins            }
7472f5b9ce6SJames Collins
7482f5b9ce6SJames Collins            if (strcasecmp($type, 'tooltip') == 0) {
749*0e73f855Snomadjimbob                $this->options['tooltip'] =         array(
750*0e73f855Snomadjimbob                    'type'     => 'text',
7512f5b9ce6SJames Collins                    'default'  => '',
7522f5b9ce6SJames Collins                    'class'    => true,
753*0e73f855Snomadjimbob                    'classNoSuffix'   => true
754*0e73f855Snomadjimbob                );
7552f5b9ce6SJames Collins            }
75618e323fdSJames Collins
75718e323fdSJames Collins            if (strcasecmp($type, 'vertical-align') == 0) {
758*0e73f855Snomadjimbob                $this->options['vertical-align'] =  array(
759*0e73f855Snomadjimbob                    'type'    => 'choice',
76018e323fdSJames Collins                    'data'    => array('top' => array('align-top'), 'middle' => array('align-middle'), 'bottom' => array('align-bottom')),
76118e323fdSJames Collins                    'default' => '',
762*0e73f855Snomadjimbob                    'class'   => true
763*0e73f855Snomadjimbob                );
76418e323fdSJames Collins            }
76518e323fdSJames Collins
76618e323fdSJames Collins            if (strcasecmp($type, 'links-match') == 0) {
767*0e73f855Snomadjimbob                $this->options['links-match'] =     array(
768*0e73f855Snomadjimbob                    'type'    => 'boolean',
76918e323fdSJames Collins                    'default' => 'false',
770*0e73f855Snomadjimbob                    'class'   => true
771*0e73f855Snomadjimbob                );
77218e323fdSJames Collins            }
7737935713eSJames Collins        }
7747935713eSJames Collins    }
7757935713eSJames Collins
7767935713eSJames Collins
7777935713eSJames Collins    /*
7787935713eSJames Collins    * Find HTML tags in string. Parse tags options. Used in parsing subtags
7797935713eSJames Collins    *
7807935713eSJames Collins    * @param $tagName       tagName to search for. Name is exclusive
7817935713eSJames Collins    * @param $content       search within content
7827935713eSJames Collins    * @param $options       parse options similar to syntax element options
783f0df6cccSJames Collins    * @param $hasEndTag     tagName search also looks for an end tag
7847935713eSJames Collins    * @return               array of tags containing 'options' => array of 'name' => 'value', 'content' => content inside the tag
7857935713eSJames Collins    */
786*0e73f855Snomadjimbob    protected function findTags($tagName, $content, $options, $hasEndTag = true)
787*0e73f855Snomadjimbob    {
7887935713eSJames Collins        $items = array();
789f0df6cccSJames Collins        $search = '/<(?i:' . $tagName . ')(.*?)>(.*?)<\/(?i:' . $tagName . ')>/s';
7907935713eSJames Collins
791f0df6cccSJames Collins        if (!$hasEndTag) {
792f0df6cccSJames Collins            $search = '/<(?i:' . $tagName . ')(.*?)>/s';
793f0df6cccSJames Collins        }
794f0df6cccSJames Collins
795f0df6cccSJames Collins        if (preg_match_all($search, $content, $match)) {
7967935713eSJames Collins            if (count($match) >= 2) {
7977935713eSJames Collins                for ($i = 0; $i < count($match[1]); $i++) {
7987935713eSJames Collins                    $item = array('options' => array(), 'content' => $this->render_text($match[2][$i]));
7997935713eSJames Collins
8007935713eSJames Collins                    $optionlist = preg_split('/\s(?=([^"]*"[^"]*")*[^"]*$)/', trim($match[1][$i]));
8017935713eSJames Collins
8027935713eSJames Collins                    foreach ($optionlist as $option) {
8037935713eSJames Collins                        $j = strpos($option, '=');
8047935713eSJames Collins                        if ($j !== false) {
8057935713eSJames Collins                            $value = substr($option, $j + 1);
8067935713eSJames Collins
8077935713eSJames Collins                            if (substr($value, 0, 1) == '"') $value = substr($value, 1);
8087935713eSJames Collins                            if (substr($value, -1) == '"') $value = substr($value, 0, -1);
8097935713eSJames Collins
8107935713eSJames Collins                            $item['options'][substr($option, 0, $j)] = $value;
8117935713eSJames Collins                        } else {
8127935713eSJames Collins                            $item['options'][$option] = true;
8137935713eSJames Collins                        }
8147935713eSJames Collins                    }
8157935713eSJames Collins
8163cbf07a0SJames Collins                    $item['options'] = $this->cleanOptions($item['options'], $options);
8177935713eSJames Collins
8187935713eSJames Collins                    $items[] = $item;
8197935713eSJames Collins                }
8207935713eSJames Collins            }
8217935713eSJames Collins        }
8227935713eSJames Collins
8237935713eSJames Collins        return $items;
8247935713eSJames Collins    }
82531359b6fSJames Collins}
826