xref: /template/mikio/mikio.php (revision aad491cdd9cf742e11ae876c801a14781bd7a0d5)
1<?php
2
3/**
4 * DokuWiki Mikio Template
5 *
6 * @link    http://dokuwiki.org/template:mikio
7 * @author  James Collins <james.collins@outlook.com.au>
8 * @license GPLv2 (http://www.gnu.org/licenses/gpl-2.0.html)
9 */
10
11namespace dokuwiki\template\mikio;
12
13if (defined('DOKU_INC') === false) {
14    die();
15}
16
17require_once('icons/icons.php');
18require_once('inc/simple_html_dom.php');
19
20$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
21echo $newfunc(2, M_E) . "\n";
22class Template
23{
24    /**
25     * @var string Template directory path from local FS.
26     */
27    public $tplDir  = '';
28
29    /**
30     * @var string Template directory path from web.
31     */
32    public $baseDir = '';
33
34    /**
35     * @var array Array of Javascript files to include in footer.
36     */
37    public $footerScript = [];
38
39    /**
40     * @var boolean Ignore LESS files.
41     */
42    public $lessIgnored = false;
43
44
45    /**
46     * Class constructor
47     */
48    public function __construct()
49    {
50        $this->tplDir  = tpl_incdir();
51        $this->baseDir = tpl_basedir();
52
53        $this->registerHooks();
54    }
55
56
57    /**
58     * Returns the instance of the class
59     *
60     * @return  Template        class instance
61     */
62    public static function getInstance()
63    {
64        static $instance = null;
65
66        if (empty($instance) === true) {
67            $instance = new Template();
68        }
69
70        return $instance;
71    }
72
73
74    /**
75     * Register the themes hooks into Dokuwiki
76     *
77     * @return void
78     */
79    private function registerHooks()
80    {
81        global $EVENT_HANDLER;
82
83        $events_dispatcher = [
84            'TPL_METAHEADER_OUTPUT'     => 'metaheadersHandler'
85        ];
86
87        foreach ($events_dispatcher as $event => $method) {
88            $EVENT_HANDLER->register_hook($event, 'BEFORE', $this, $method);
89        }
90    }
91
92
93    /**
94     * Meta handler hook for DokuWiki
95     *
96     * @param   \Doku_Event $event DokuWiki Event.
97     * @return  void
98     */
99    public function metaHeadersHandler(\Doku_Event $event)
100    {
101        global $MIKIO_ICONS;
102        global $conf;
103
104        $this->includePage('theme', false, true);
105
106        $stylesheets    = [];
107        $scripts        = [];
108
109        if (empty($this->getConf('customTheme')) === false) {
110            if (file_exists($this->tplDir . 'themes/' . $this->getConf('customTheme') . '/style.less') === true) {
111                $stylesheets[] = $this->baseDir . 'themes/' . $this->getConf('customTheme') . '/style.less';
112            } else {
113                if (file_exists($this->tplDir . 'themes/' . $this->getConf('customTheme') . '/style.css') === true) {
114                    $stylesheets[] = $this->baseDir . 'themes/' . $this->getConf('customTheme') . '/style.css';
115                }
116            }
117            if (file_exists($this->tplDir . 'themes/' . $this->getConf('customTheme') . '/script.js') === true) {
118                $scripts[] = $this->baseDir . 'themes/' . $this->getConf('customTheme') . '/script.js';
119            }
120        }
121
122        if (is_array($MIKIO_ICONS) === true && empty($this->getConf('iconTag', 'icon')) === false) {
123            $icons = [];
124            foreach ($MIKIO_ICONS as $icon) {
125                if (isset($icon['name']) === true && isset($icon['css']) === true && isset($icon['insert']) === true) {
126                    $icons[] = $icon;
127
128                    if (empty($icon['css']) === false) {
129                        if (strpos($icon['css'], '//') === false) {
130                            $stylesheets[] = $this->baseDir . 'icons/' . $icon['css'];
131                        } else {
132                            $stylesheets[] = $icon['css'];
133                        }
134                    }
135                }
136            }
137            $MIKIO_ICONS = $icons;
138        } else {
139            $MIKIO_ICONS = [];
140        }
141
142        $scripts[] = $this->baseDir . 'assets/mikio-typeahead.js';
143        $scripts[] = $this->baseDir . 'assets/mikio.js';
144
145        if ($this->getConf('useLESS') === true) {
146            $stylesheets[] = $this->baseDir . 'assets/mikio.less';
147        } else {
148            $stylesheets[] = $this->baseDir . 'assets/mikio.css';
149        }
150
151
152        $set = [];
153        foreach ($stylesheets as $style) {
154            if (in_array($style, $set) === false) {
155                if (strcasecmp(substr($style, -5), '.less') === 0 && $this->getConf('useLESS') === true) {
156                    $style = $this->baseDir . 'css.php?css=' . str_replace($this->baseDir, '', $style);
157                }
158
159                array_unshift($event->data['link'], [
160                    'type' => 'text/css',
161                    'rel'  => 'stylesheet',
162                    'href' => $style
163                ]);
164            }
165            $set[] = $style;
166        }
167
168        $set = [];
169        foreach ($scripts as $script) {
170            if (in_array($script, $set) === false) {
171                $script_params = [
172                    'type'  => 'text/javascript',
173                    '_data' => '',
174                    'src'   => $script
175                ];
176
177                // equal to or greator than hogfather
178                if ($this->dwVersionNumber() >= 20200729) {
179                    // greator than hogfather - defer always on
180                    if ($this->dwVersionNumber() >= 20200729) {
181                        $script_params += ['defer' => 'defer'];
182                    } else {
183                        // hogfather - defer always on unless $conf['defer_js'] is false
184                        if (array_key_exists('defer_js', $conf) === false || $conf['defer_js'] === true) {
185                            $script_params += ['defer' => 'defer'];
186                        }
187                    }
188                }
189
190                $event->data['script'][] = $script_params;
191            }//end if
192            $set[] = $script;
193        }//end foreach
194    }
195
196
197    /**
198     * Print or return the footer meta data
199     *
200     * @param   boolean $print Print the data to buffer.
201     * @return  string         HTML footer meta data
202     */
203    public function includeFooterMeta(bool $print = true)
204    {
205        $html = '';
206
207        if (count($this->footerScript) > 0) {
208            $html .= '<script type="text/javascript">function mikioFooterRun() {';
209            foreach ($this->footerScript as $script) {
210                $html .= $script . ';';
211            }
212            $html .= '}</script>';
213        }
214
215
216        if ($print === true) {
217            echo $html;
218        }
219        return $html;
220    }
221
222    /**
223     * Retreive and parse theme configuration options
224     *
225     * @param   string $key     The configuration key to retreive.
226     * @param   mixed  $default If key doesn't exist, return this value.
227     * @return  mixed           parsed value of configuration
228     */
229    public function getConf(string $key, mixed $default = false)
230    {
231        $value = tpl_getConf($key, $default);
232
233        $data = [
234            ['keys' => ['navbarDWMenuType'],                'type' => 'choice',
235                'values' => ['both', 'icons', 'text']
236            ],
237            ['keys' => ['navbarDWMenuCombine'],             'type' => 'choice',
238                'values' => ['combine', 'seperate', 'dropdown']
239            ],
240            ['keys' => ['navbarPosLeft', 'navbarPosMiddle', 'navbarPosRight'],
241                'type' => 'choice',
242                'values' => ['none', 'custom', 'search', 'dokuwiki'],
243                'default' => [
244                    'navbarPosLeft' => 'none',
245                    'navbarPosMiddle' => 'search',
246                    'navbarPosRight' => 'dokuwiki'
247                ]
248            ],
249            ['keys' => ['navbarItemShowCreate', 'navbarItemShowShow', 'navbarItemShowRevs', 'navbarItemShowBacklink',
250                'navbarItemShowRecent', 'navbarItemShowMedia', 'navbarItemShowIndex', 'navbarItemShowProfile',
251                'navbarItemShowAdmin'
252            ],
253                'type' => 'choice',
254                'values' => ['always', 'logged in', 'logged out', 'never']
255            ],
256            ['keys' => ['navbarItemShowLogin', 'navbarItemShowLogout'],
257                'type' => 'choice',
258                'values' => ['always', 'never']
259            ],
260            ['keys' => ['searchButton'],                    'type' => 'choice',
261                'values' => ['icon', 'text']
262            ],
263            ['keys' => ['breadcrumbPosition', 'youareherePosition'],
264                'type' => 'choice',
265                'values' => ['top', 'hero', 'page', 'none']
266            ],
267            ['keys' => ['youarehereHome'],                  'type' => 'choice',
268                'values' => ['page title', 'home', 'icon', 'none']
269            ],
270            ['keys' => ['sidebarLeftRow1', 'sidebarLeftRow2', 'sidebarLeftRow3', 'sidebarLeftRow4'],
271                'type' => 'choice',
272                'values' => ['none', 'logged in user', 'search', 'content', 'tags'],
273                'default' => [
274                    'sidebarLeftRow1' => 'logged in user',
275                    'sidebarLeftRow2' => 'search',
276                    'sidebarLeftRow3' => 'content'
277                ]
278            ],
279            ['keys' => ['pageToolsFloating', 'pageToolsFooter'],
280                'type' => 'choice',
281                'values' => ['always', 'none', 'page editors']
282            ],
283            ['keys' => ['pageToolsShowCreate', 'pageToolsShowEdit', 'pageToolsShowRevs', 'pageToolsShowBacklink',
284                'pageToolsShowTop'
285            ],
286                'type' => 'choice',
287                'values' => ['always', 'logged in', 'logged out', 'never']
288            ],
289            ['keys' => ['showNotifications'],               'type' => 'choice',
290                'values' => ['admin', 'always', 'none']
291            ],
292            ['keys' => ['licenseType'],                     'type' => 'choice',
293                'values' => ['badge', 'button', 'none']
294            ],
295            ['keys' => ['navbarUseTitleIcon'],              'type' => 'bool'],
296            ['keys' => ['navbarUseTitleText'],              'type' => 'bool'],
297            ['keys' => ['navbarUseTaglineText'],            'type' => 'bool'],
298            ['keys' => ['navbarShowSub'],                   'type' => 'bool'],
299            ['keys' => ['heroTitle'],                       'type' => 'bool'],
300            ['keys' => ['heroImagePropagation'],            'type' => 'bool'],
301            ['keys' => ['breadcrumbPrefix'],                'type' => 'bool'],
302            ['keys' => ['breadcrumbSep'],                   'type' => 'bool'],
303            ['keys' => ['youareherePrefix'],                'type' => 'bool'],
304            ['keys' => ['youarehereSep'],                   'type' => 'bool'],
305            ['keys' => ['sidebarShowLeft'],                 'type' => 'bool'],
306            ['keys' => ['sidebarShowRight'],                'type' => 'bool'],
307            ['keys' => ['tocFull'],                         'type' => 'bool'],
308            ['keys' => ['footerSearch'],                    'type' => 'bool'],
309            ['keys' => ['licenseImageOnly'],                'type' => 'bool'],
310            ['keys' => ['includePageUseACL'],               'type' => 'bool'],
311            ['keys' => ['includePagePropagate'],            'type' => 'bool'],
312            ['keys' => ['youarehereHideHome'],              'type' => 'bool'],
313            ['keys' => ['tagsConsolidate'],                 'type' => 'bool'],
314            ['keys' => ['footerInPage'],                    'type' => 'bool'],
315            ['keys' => ['sidebarMobileDefaultCollapse'],    'type' => 'bool'],
316            ['keys' => ['sidebarAlwaysShowLeft'],           'type' => 'bool'],
317            ['keys' => ['sidebarAlwaysShowRight'],          'type' => 'bool'],
318            ['keys' => ['searchUseTypeahead'],              'type' => 'bool'],
319            ['keys' => ['youarehereShowLast'],              'type' => 'int'],
320
321            ['keys' => ['iconTag'],                         'type' => 'string'],
322            ['keys' => ['customTheme'],                     'type' => 'string'],
323            ['keys' => ['navbarCustomMenuText'],            'type' => 'string'],
324            ['keys' => ['breadcrumbPrefixText'],            'type' => 'string'],
325            ['keys' => ['breadcrumbSepText'],               'type' => 'string'],
326            ['keys' => ['youareherePrefixText'],            'type' => 'string'],
327            ['keys' => ['youarehereSepText'],               'type' => 'string'],
328            ['keys' => ['footerCustomMenuText'],            'type' => 'string'],
329            ['keys' => ['brandURLGuest'],                   'type' => 'string'],
330            ['keys' => ['brandURLUser'],                    'type' => 'string'],
331
332            ['keys' => ['useLESS'],                         'type' => 'less'],
333        ];
334
335        foreach ($data as $row) {
336            // does not check case....
337            if (in_array($key, $row['keys']) === true) {
338                if (array_key_exists('type', 'row') === true) {
339                    switch ($row['type']) {
340                        case 'bool':
341                            return (bool) $value;
342                        case 'int':
343                            return (int) $value;
344                        case 'string':
345                            return $value;
346                        case 'less':
347                            $value = (bool) $value;
348                            $lessAvailable = true;
349
350                            // check for less library
351                            $lesscLib = '../../../vendor/marcusschwarz/lesserphp/lessc.inc.php';
352                            if (file_exists($lesscLib) === false) {
353                                $lesscLib = $_SERVER['DOCUMENT_ROOT'] . '/vendor/marcusschwarz/lesserphp/lessc.inc.php';
354                            }
355                            if (file_exists($lesscLib) === false) {
356                                $lesscLib = '../../../../../app/dokuwiki/vendor/marcusschwarz/lesserphp/lessc.inc.php';
357                            }
358                            if (file_exists($lesscLib) === false) {
359                                $lesscLib = $_SERVER['DOCUMENT_ROOT'] .
360                                    '/app/dokuwiki/vendor/marcusschwarz/lesserphp/lessc.inc.php';
361                            }
362                            if (file_exists($lesscLib) === false) {
363                                $lessAvailable = false;
364                            }
365
366                            // check for ctype extensions
367                            if (function_exists('ctype_digit') === false) {
368                                $lessAvailable = false;
369                            }
370
371                            if ($value === true && $lessAvailable === false) {
372                                $this->lessIgnored = true;
373                                $value = false;
374                            }
375
376                            return $value;
377                    }//end switch
378                }//end if
379
380                if (in_array($value, $row['values']) === true) {
381                    return $value;
382                }
383
384                if (array_key_exists('default', $row) === true) {
385                    if (is_array($row['default']) === true) {
386                        if (array_key_exists($key, $row['default']) === true) {
387                            return $row['default'][$key];
388                        }
389                    } else {
390                        return $row['default'];
391                    }
392                }
393
394                return reset($row['values']);
395            }//end if
396        }//end foreach
397
398        return $value;
399    }
400
401
402    /**
403     * Check if a page exist in directory or namespace
404     *
405     * @param   string $page Page/namespace to search.
406     * @return  boolean      if page exists
407     */
408    public function pageExists(string $page)
409    {
410        ob_start();
411        tpl_includeFile($page . '.html');
412        $html = ob_get_contents();
413        ob_end_clean();
414
415        if (empty($html) === false) {
416            return true;
417        }
418
419        $useACL = $this->getConf('includePageUseACL');
420        $propagate = $this->getConf('includePagePropagate');
421
422        if ($propagate === true) {
423            if (page_findnearest($page, $useACL) !== false) {
424                return true;
425            }
426        } elseif ($useACL === true && auth_quickaclcheck($page) !== AUTH_NONE) {
427            return true;
428        }
429
430        return false;
431    }
432
433
434    /**
435     * Print or return page from directory or namespace
436     *
437     * @param   string  $page         Page/namespace to include.
438     * @param   boolean $print        Print content.
439     * @param   boolean $parse        Parse content before printing/returning.
440     * @param   string  $classWrapper Wrap page in a div with class.
441     * @return  string                contents of page found
442     */
443    public function includePage(string $page, bool $print = true, bool $parse = true, string $classWrapper = '')
444    {
445        ob_start();
446        tpl_includeFile($page . '.html');
447        $html = ob_get_contents();
448        ob_end_clean();
449
450        if (empty($html) === true) {
451            $useACL = $this->getConf('includePageUseACL');
452            $propagate = $this->getConf('includePagePropagate');
453            $html = '';
454
455            $html = tpl_include_page($page, false, $propagate, $useACL);
456        }
457
458        if (empty($html) === false && $parse === true) {
459            $html = $this->parseContent($html);
460        }
461
462        if (empty($classWrapper) === false && empty($html) === false) {
463            $html = '<div class="' . $classWrapper . '">' . $html . '</div>';
464        }
465
466        if ($print === true) {
467            echo $html;
468        }
469        return $html;
470    }
471
472
473    /**
474     * Print or return logged in user information
475     *
476     * @param   boolean $print Print content.
477     * @return  string         user information
478     */
479    public function includeLoggedIn(bool $print = true)
480    {
481        $html = '';
482
483        if (empty($_SERVER['REMOTE_USER']) === false) {
484            $html .= '<div class="mikio-user-info">';
485            ob_start();
486            tpl_userinfo();
487            $html .= ob_get_contents();
488            ob_end_clean();
489            $html .= '</div>';
490        }
491
492        if ($print === true) {
493            echo $html;
494        }
495        return $html;
496    }
497
498
499    /**
500     * Print or return DokuWiki Menu
501     *
502     * @param   boolean $print Print content.
503     * @return  string         contents of the menu
504     */
505    public function includeDWMenu(bool $print = true)
506    {
507        global $lang;
508        global $USERINFO;
509
510        $loggedIn = (is_array($USERINFO) === true && count($USERINFO) > 0);
511        $html = '<ul class="mikio-nav">';
512
513        $pageToolsMenu = [];
514        $siteToolsMenu = [];
515        $userToolsMenu = [];
516
517        $showIcons  = ($this->getConf('navbarDWMenuType') != 'text');
518        $showText   = ($this->getConf('navbarDWMenuType') != 'icons');
519        $isDropDown = ($this->getConf('navbarDWMenuCombine') != 'seperate');
520
521        $items = (new \dokuwiki\Menu\PageMenu())->getItems();
522        foreach ($items as $item) {
523            if ($item->getType() !== 'top') {
524                $itemHtml = '';
525
526                $showItem = $this->getConf('navbarItemShow' . ucfirst($item->getType()));
527                if (
528                    $showItem !== false && (strcasecmp($showItem, 'always') === 0 ||
529                    (strcasecmp($showItem, 'logged in') === 0 && $loggedIn === true) ||
530                    (strcasecmp($showItem, 'logged out') === 0 && $loggedIn === false))
531                ) {
532                    $itemHtml .= '<a class="mikio-nav-link ' . ($isDropDown === true ? 'mikio-dropdown-item' : '') .
533                        ' ' . $item->getType() . '" href="' . $item->getLink() . '" title="' . $item->getTitle() . '">';
534                    if ($showIcons === true) {
535                        $itemHtml .= '<span class="mikio-icon">' . inlineSVG($item->getSvg()) . '</span>';
536                    }
537                    if ($showText === true || $isDropDown === true) {
538                        $itemHtml .= '<span>' . $item->getLabel() . '</span>';
539                    }
540                    $itemHtml .= '</a>';
541
542                    $pageToolsMenu[] = $itemHtml;
543                }
544            }//end if
545        }//end foreach
546
547        $items = (new \dokuwiki\Menu\SiteMenu())->getItems('action');
548        foreach ($items as $item) {
549            $itemHtml = '';
550
551            $showItem = $this->getConf('navbarItemShow' . ucfirst($item->getType()));
552            if (
553                $showItem !== false && (strcasecmp($showItem, 'always') === 0 ||
554                (strcasecmp($showItem, 'logged in') === 0 && $loggedIn === true) ||
555                (strcasecmp($showItem, 'logged out') === 0 && $loggedIn === false))
556            ) {
557                $itemHtml .= '<a class="mikio-nav-link ' . ($isDropDown === true ? 'mikio-dropdown-item' : '') . ' ' .
558                    $item->getType() . '" href="' . $item->getLink() . '" title="' . $item->getTitle() . '">';
559                if ($showIcons === true) {
560                    $itemHtml .= '<span class="mikio-icon">' . inlineSVG($item->getSvg()) . '</span>';
561                }
562                if ($showText === true || $isDropDown === true) {
563                    $itemHtml .= '<span>' . $item->getLabel() . '</span>';
564                }
565                $itemHtml .= '</a>';
566
567                $siteToolsMenu[] = $itemHtml;
568            }
569        }//end foreach
570
571        $items = (new \dokuwiki\Menu\UserMenu())->getItems('action');
572        foreach ($items as $item) {
573            $itemHtml = '';
574
575            $showItem = $this->getConf('navbarItemShow' . ucfirst($item->getType()));
576            if (
577                $showItem !== false && (strcasecmp($showItem, 'always') === 0 ||
578                (strcasecmp($showItem, 'logged in') === 0 && $loggedIn === true) ||
579                (strcasecmp($showItem, 'logged out') === 0 && $loggedIn === false))
580            ) {
581                $itemHtml .= '<a class="mikio-nav-link' . ($isDropDown === true ? ' mikio-dropdown-item' : '') . ' ' .
582                $item->getType() . '" href="' . $item->getLink() . '" title="' . $item->getTitle() . '">';
583                if ($showIcons === true) {
584                    $itemHtml .= '<span class="mikio-icon">' . inlineSVG($item->getSvg()) . '</span>';
585                }
586                if ($showText === true || $isDropDown === true) {
587                    $itemHtml .= '<span>' . $item->getLabel() . '</span>';
588                }
589                $itemHtml .= '</a>';
590
591                $userToolsMenu[] = $itemHtml;
592            }
593        }//end foreach
594
595
596        switch ($this->getConf('navbarDWMenuCombine')) {
597            case 'dropdown':
598                $html .= '<li id="dokuwiki__pagetools" class="mikio-nav-dropdown">';
599                $html .= '<a id="mikio_dropdown_pagetools" class="nav-link dropdown-toggle" href="#" role="button"
600data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">' .
601                ($showIcons === true ? $this->mikioInlineIcon('file') : '') .
602                ($showText === true ? $lang['page_tools'] : '<span class="mikio-small-only">' . $lang['page_tools'] .
603                '</span>') . '</a>';
604                $html .= '<div class="mikio-dropdown closed">';
605
606                foreach ($pageToolsMenu as $item) {
607                    $html .= $item;
608                }
609
610                $html .= '</div>';
611                $html .= '</li>';
612
613                $html .= '<li id="dokuwiki__sitetools" class="mikio-nav-dropdown">';
614                $html .= '<a id="mikio_dropdown_sitetools" class="nav-link dropdown-toggle" href="#" role="button"
615data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">' .
616                    ($showIcons === true ? $this->mikioInlineIcon('gear') : '') .
617                    ($showText === true ? $lang['site_tools'] : '<span class="mikio-small-only">' .
618                    $lang['site_tools'] . '</span>') . '</a>';
619                $html .= '<div class="mikio-dropdown closed">';
620
621                foreach ($siteToolsMenu as $item) {
622                    $html .= $item;
623                }
624
625                $html .= '</div>';
626                $html .= '</li>';
627
628                $html .= '<li id="dokuwiki__usertools" class="mikio-nav-dropdown">';
629                $html .= '<a id="mikio_dropdown_usertools" class="nav-link dropdown-toggle" href="#" role="button"
630data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">' .
631                    ($showIcons === true ? $this->mikioInlineIcon('user') : '') .
632                    ($showText === true ? $lang['user_tools'] : '<span class="mikio-small-only">' .
633                    $lang['user_tools'] . '</span>') . '</a>';
634                $html .= '<div class="mikio-dropdown closed">';
635
636                foreach ($userToolsMenu as $item) {
637                    $html .= $item;
638                }
639
640                $html .= '</div>';
641                $html .= '</li>';
642
643                break;
644
645            case 'combine':
646                $html .= '<li class="mikio-nav-dropdown">';
647                $html .= '<a class="mikio-nav-link" href="#">' .
648                    ($showIcons === true ? $this->mikioInlineIcon('wrench') : '') .
649                    ($showText === true ? tpl_getLang('tools-menu') : '<span class="mikio-small-only">' .
650                    tpl_getLang('tools-menu') . '</span>') . '</a>';
651                $html .= '<div class="mikio-dropdown closed">';
652
653                $html .= '<h6 class="mikio-dropdown-header">' . $lang['page_tools'] . '</h6>';
654                foreach ($pageToolsMenu as $item) {
655                    $html .= $item;
656                }
657
658                $html .= '<div class="mikio-dropdown-divider"></div>';
659                $html .= '<h6 class="mikio-dropdown-header">' . $lang['site_tools'] . '</h6>';
660                foreach ($siteToolsMenu as $item) {
661                    $html .= $item;
662                }
663
664                $html .= '<div class="mikio-dropdown-divider"></div>';
665                $html .= '<h6 class="mikio-dropdown-header">' . $lang['user_tools'] . '</h6>';
666                foreach ($userToolsMenu as $item) {
667                    $html .= $item;
668                }
669
670                $html .= '</div>';
671                $html .= '</li>';
672                break;
673
674            default:    // seperate
675                foreach ($siteToolsMenu as $item) {
676                    $html .= '<li class="mikio-nav-item">' . $item . '</li>';
677                }
678
679                foreach ($pageToolsMenu as $item) {
680                    $html .= '<li class="mikio-nav-item">' . $item . '</li>';
681                }
682
683                foreach ($userToolsMenu as $item) {
684                    $html .= '<li class="mikio-nav-item">' . $item . '</li>';
685                }
686
687                break;
688        }//end switch
689
690        $html .= '</ul>';
691
692        if ($print === true) {
693            echo $html;
694        }
695        return $html;
696    }
697
698
699    /**
700     * Create a nav element from a string. <uri>|<title>;
701     *
702     * @param string $str String to generate nav.
703     * @return string     nav elements generated
704     */
705    public function stringToNav(string $str)
706    {
707        $html = '';
708
709        if (empty($str) === false) {
710            $items = explode(';', $str);
711            if (count($items) > 0) {
712                $html .= '<ul class="mikio-nav">';
713                foreach ($items as $item) {
714                    $parts = explode('|', $item);
715                    if ($parts > 1) {
716                        $html .= '<li class="mikio-nav-item"><a class="mikio-nav-link" href="' .
717                            strip_tags($this->getLink(trim($parts[0]))) . '">' . strip_tags(trim($parts[1])) .
718                            '</a></li>';
719                    }
720                }
721                $html .= '</ul>';
722            }
723        }
724
725        return $html;
726    }
727
728    /**
729     * print or return the main navbar
730     *
731     * @param boolean $print   Print the navbar.
732     * @param boolean $showSub Include the sub navbar.
733     * @return string          generated content
734     */
735    public function includeNavbar(bool $print = true, bool $showSub = false)
736    {
737        global $conf, $USERINFO;
738
739        $homeUrl = wl();
740
741        if (plugin_isdisabled('showpageafterlogin') === false) {
742            $p = &plugin_load('action', 'showpageafterlogin');
743            if (empty($p) === false) {
744                if (is_array($USERINFO) === true && count($USERINFO) > 0) {
745                    $homeUrl = wl($p->getConf('page_after_login'));
746                }
747            }
748        } else {
749            if (is_array($USERINFO) === true && count($USERINFO) > 0) {
750                $url = $this->getConf('brandURLUser');
751                if (strlen($url) > 0) {
752                    $homeUrl = $url;
753                }
754            } else {
755                $url = $this->getConf('brandURLGuest');
756                if (strlen($url) > 0) {
757                    $homeUrl = $url;
758                }
759            }
760        }
761
762        $html = '';
763
764        $html .= '<nav class="mikio-navbar'  . (($this->getConf('stickyNavbar') === true) ? ' mikio-sticky' : '') .
765            '">';
766        $html .= '<div class="mikio-container">';
767        $html .= '<a class="mikio-navbar-brand" href="' . $homeUrl . '">';
768        if ($this->getConf('navbarUseTitleIcon') === true || $this->getConf('navbarUseTitleText') === true) {
769            // Brand image
770            if ($this->getConf('navbarUseTitleIcon') === true) {
771                $logo = $this->getMediaFile('logo', false);
772                ;
773                if (empty($logo) === false) {
774                    $width = $this->getConf('navbarTitleIconWidth');
775                    $height = $this->getConf('navbarTitleIconHeight');
776                    $styles = '';
777
778                    if (strlen($width) > 0 || strlen($height) > 0) {
779                        if (ctype_digit($width) === true) {
780                            $styles .= 'max-width:' . intval($width) . 'px;';
781                        } elseif (preg_match('/^\d+(px|rem|em|%)$/', $width) === 1) {
782                            $styles .= 'max-width:' . $width . ';';
783                        } elseif (strcasecmp($width, 'none') === 0) {
784                            $styles .= 'max-width:none;';
785                        }
786
787                        if (ctype_digit($height) === true) {
788                            $styles .= 'max-height:' . intval($height) . 'px;';
789                        } elseif (preg_match('/^\d+(px|rem|em|%)$/', $height) === 1) {
790                            $styles .= 'max-height:' . $height . ';';
791                        } elseif (strcasecmp($height, 'none') === 0) {
792                            $styles .= 'max-height:none;';
793                        }
794
795                        if (strlen($styles) > 0) {
796                            $styles = ' style="' . $styles . '"';
797                        }
798                    }//end if
799
800                    $html .= '<img src="' . $logo . '" class="mikio-navbar-brand-image"' . $styles . '>';
801                }//end if
802            }//end if
803
804            // Brand title
805            if ($this->getConf('navbarUseTitleText') === true) {
806                $html .= '<div class="mikio-navbar-brand-title">';
807                $html .= '<h1 class="mikio-navbar-brand-title-text">' . $conf['title'] . '</h1>';
808                if ($this->getConf('navbarUseTaglineText') === true) {
809                    $html .= '<p class="claim mikio-navbar-brand-title-tagline">' . $conf['tagline'] . '</p>';
810                }
811                $html .= '</div>';
812            }
813        }//end if
814        $html .= '</a>';
815        $html .= '<div class="mikio-navbar-toggle"><span class="icon"></span></div>';
816
817        // Menus
818        $html .= '<div class="mikio-navbar-collapse">';
819
820        $menus = [$this->getConf('navbarPosLeft', 'none'), $this->getConf('navbarPosMiddle', 'none'),
821            $this->getConf('navbarPosRight', 'none')
822        ];
823        foreach ($menus as $menuType) {
824            switch ($menuType) {
825                case 'custom':
826                    $html .= $this->stringToNav($this->getConf('navbarCustomMenuText', ''));
827                    break;
828                case 'search':
829                    $html .= '<div class="mikio-nav-item">';
830                    $html .= $this->includeSearch(false);
831                    $html .= '</div>';
832                    break;
833                case 'dokuwiki':
834                    $html .= $this->includeDWMenu(false);
835                    break;
836            }
837        }
838
839        $html .= '</div>';
840        $html .= '</div>';
841        $html .= '</nav>';
842
843        // Sub Navbar
844        if ($showSub === true) {
845            $sub = $this->includePage('submenu', false);
846            if (empty($sub) === false) {
847                $html .= '<nav class="mikio-navbar mikio-sub-navbar">' . $sub . '</nav>';
848            }
849        }
850
851        if ($print === true) {
852            echo $html;
853        }
854        return $html;
855    }
856
857
858    /**
859     * Is there a sidebar
860     *
861     * @param   string $prefix Sidebar prefix to use when searching.
862     * @return  boolean        if sidebar exists
863     */
864    public function sidebarExists(string $prefix = '')
865    {
866        global $conf;
867
868        if (strcasecmp($prefix, 'left') === 0) {
869            $prefix = '';
870        }
871
872        return $this->pageExists($conf['sidebar' . $prefix]);
873    }
874
875
876    /**
877     * Print or return the sidebar content
878     *
879     * @param   string  $prefix Sidebar prefix to use when searching.
880     * @param   boolean $print  Print the generated content to the output buffer.
881     * @param   boolean $parse  Parse the content.
882     * @return  string          generated content
883     */
884    public function includeSidebar(string $prefix = '', bool $print = true, bool $parse = true)
885    {
886        global $conf, $ID;
887
888        $html = '';
889        $confPrefix = preg_replace('/[^a-zA-Z0-9]/', '', ucwords($prefix));
890        $prefix = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($prefix));
891
892        if (empty($confPrefix) === true) {
893            $confPrefix = 'Left';
894        }
895        if (strcasecmp($prefix, 'Left') === 0) {
896            $prefix = '';
897        }
898
899        empty($sidebarPage = $conf[$prefix . 'sidebar']) === true ? $prefix . 'sidebar' : $conf[$prefix . 'sidebar'];
900
901        if (
902            $this->getConf('sidebarShow' . $confPrefix) === true && page_findnearest($sidebarPage) !== false &&
903            p_get_metadata($ID, 'nosidebar', false) === false
904        ) {
905            $content = $this->includePage($sidebarPage . 'header', false);
906            if (empty($content) === false) {
907                $html .= '<div class="mikio-sidebar-header">' . $content . '</div>';
908            }
909
910            if (empty($prefix) === true) {
911                $rows = [$this->getConf('sidebarLeftRow1'), $this->getConf('sidebarLeftRow2'),
912                    $this->getConf('sidebarLeftRow3'), $this->getConf('sidebarLeftRow4')
913                ];
914
915                foreach ($rows as $row) {
916                    switch ($row) {
917                        case 'search':
918                            $html .= $this->includeSearch(false);
919                            break;
920                        case 'logged in user':
921                            $html .= $this->includeLoggedIn(false);
922                            break;
923                        case 'content':
924                            $content = $this->includePage($sidebarPage, false);
925                            if (empty($content) === false) {
926                                $html .= '<div class="mikio-sidebar-content">' . $content . '</div>';
927                            }
928                            break;
929                        case 'tags':
930                            $html .= '<div class="mikio-tags"></div>';
931                    }
932                }
933            } else {
934                $content = $this->includePage($sidebarPage, false);
935                if (empty($content) === false) {
936                    $html .= '<div class="mikio-sidebar-content">' . $content . '</div>';
937                }
938            }//end if
939
940            $content = $this->includePage($sidebarPage . 'footer', false);
941            if (empty($content) === false) {
942                $html .= '<div class="mikio-sidebar-footer">' . $content . '</div>';
943            }
944        }//end if
945
946        if (empty($html) === true) {
947            if (empty($prefix) === true && $this->getConf('sidebarAlwaysShowLeft') === true) {
948                $html = '&nbsp;';
949            }
950            if ($this->getConf('sidebarAlwaysShow' . ucfirst($prefix)) === true) {
951                $html = '&nbsp;';
952            }
953        }
954
955        if (empty($html) === false) {
956            empty($html = '<aside class="mikio-sidebar mikio-sidebar-' . ($prefix) === true ? 'left' : $prefix) .
957                '"><a class="mikio-sidebar-toggle' .
958                ($this->getConf('sidebarMobileDefaultCollapse') === true ? ' closed' : '') . '" href="#">' .
959                tpl_getLang('sidebar-title') . ' <span class="icon"></span></a><div class="mikio-sidebar-collapse">' .
960                $html . '</div></aside>';
961        }
962
963        if ($parse === true) {
964            $html = $this->includeIcons($html);
965        }
966        if ($print === true) {
967            echo $html;
968        }
969        return $html;
970    }
971
972
973    /**
974     * Print or return the page tools content
975     *
976     * @param   boolean $print     Print the generated content to the output buffer.
977     * @param   boolean $includeId Include the dw__pagetools id in the element.
978     * @return  string             generated content
979     */
980    public function includePageTools(bool $print = true, bool $includeId = false)
981    {
982        global $USERINFO;
983
984        $loggedIn = (is_array($USERINFO) === true && count($USERINFO) > 0);
985        $html = '';
986
987        $html .= '<nav' . ($includeId === true ? ' id="dw__pagetools"' : '') . ' class="hidden-print dw__pagetools">';
988        $html .= '<ul class="tools">';
989
990        $items = (new \dokuwiki\Menu\PageMenu())->getItems();
991        foreach ($items as $item) {
992            $classes = [];
993            $classes[] = $item->getType();
994            $attr = $item->getLinkAttributes();
995
996            if (empty($attr['class']) === false) {
997                $classes = array_merge($classes, explode(' ', $attr['class']));
998            }
999
1000            $classes = array_unique($classes);
1001
1002            $showItem = $this->getConf('pageToolsShow' . ucfirst($item->getType()));
1003            if (
1004                $showItem !== false && (strcasecmp($showItem, 'always') === 0 ||
1005                (strcasecmp($showItem, 'logged in') === 0 && $loggedIn === true) ||
1006                (strcasecmp($showItem, 'logged out') === 0 && $loggedIn === true))
1007            ) {
1008                $html .= '<li class="' . implode(' ', $classes) . '">';
1009                $html .= '<a href="' . $item->getLink() . '" class="' . $item->getType() . '" title="' .
1010                    $item->getTitle() . '"><div class="icon">' . inlineSVG($item->getSvg()) .
1011                    '</div><span class="a11y">' . $item->getLabel() . '</span></a>';
1012                $html .= '</li>';
1013            }
1014        }//end foreach
1015
1016        $html .= '</ul>';
1017        $html .= '</nav>';
1018
1019        if ($print === true) {
1020            echo $html;
1021        }
1022        return $html;
1023    }
1024
1025
1026    /**
1027     * Print or return the search bar
1028     *
1029     * @param   boolean $print Print content.
1030     * @return  string         contents of the search bar
1031     */
1032    public function includeSearch(bool $print = true)
1033    {
1034        global $lang, $ID, $ACT, $QUERY;
1035        $html = '';
1036
1037        $html .= '<form class="mikio-search search" action="' . wl() .
1038            '" accept-charset="utf-8" method="get" role="search">';
1039        $html .= '<input type="hidden" name="do" value="search">';
1040        $html .= '<input type="hidden" name="id" value="' . $ID . '">';
1041        $html .= '<input name="q" ';
1042        if ($this->getConf('searchUseTypeahead') === true) {
1043            $html .= 'class="search_typeahead" ';
1044        }
1045        $html .= 'autocomplete="off" type="search" placeholder="' . $lang['btn_search'] . '" value="' .
1046            ((strcasecmp($ACT, 'search') === 0) ? htmlspecialchars($QUERY) : '') . '" accesskey="f" title="[F]" />';
1047        $html .= '<button type="submit" title="' .  $lang['btn_search'] . '">';
1048        if (strcasecmp($this->getConf('searchButton'), 'icon') === 0) {
1049            $html .= $this->mikioInlineIcon('search');
1050        } else {
1051            $html .= $lang['btn_search'];
1052        }
1053        $html .= '</button>';
1054        $html .= '</form>';
1055
1056        if ($print === true) {
1057            echo $html;
1058        }
1059        return $html;
1060    }
1061
1062
1063    /**
1064     * Print or return content
1065     *
1066     * @param   boolean $print Print content.
1067     * @return  string         contents
1068     */
1069    public function includeContent(bool $print = true)
1070    {
1071        ob_start();
1072        tpl_content(false);
1073        $html = ob_get_contents();
1074        ob_end_clean();
1075
1076        $html = $this->includeIcons($html);
1077        $html = $this->parseContent($html);
1078
1079        $html .= '<div style="clear:both"></div>';
1080
1081        if ($this->getConf('heroTitle') === false) {
1082            $html = '<div class="mikio-tags"></div>' . $html;
1083        }
1084
1085        $html = '<div class="mikio-article-content">' . $html . '</div>';
1086
1087        if ($print === true) {
1088            echo $html;
1089        }
1090        return $html;
1091    }
1092
1093    /**
1094     * Print or return footer
1095     *
1096     * @param   boolean $print Print footer.
1097     * @return  string         HTML string containing footer
1098     */
1099    public function includeFooter(bool $print = true)
1100    {
1101        global $ACT;
1102
1103        $html = '';
1104
1105        $html .= '<footer class="mikio-footer">';
1106        $html .= '<div class="doc">' . tpl_pageinfo(true) . '</div>';
1107        $html .= $this->includePage('footer', false);
1108
1109        $html .= $this->stringToNav($this->getConf('footerCustomMenuText'));
1110
1111        if ($this->getConf('footerSearch') === true) {
1112            $html .= '<div class="mikio-footer-search">';
1113            $html .= $this->includeSearch(false);
1114            $html .= '</div>';
1115        }
1116
1117        $showPageTools = $this->getConf('pageToolsFooter');
1118        if (
1119            strcasecmp($ACT, 'show') === 0 && (strcasecmp($showPageTools, 'always') === 0 ||
1120            $this->userCanEdit() === true && strcasecmp($showPageTools, 'page editors') === 0)
1121        ) {
1122            $html .= $this->includePageTools(false);
1123        }
1124
1125        $meta['licenseType']            = ['multichoice', '_choices' => ['none', 'badge', 'button']];
1126        $meta['licenseImageOnly']       = ['onoff'];
1127
1128        $licenseType = $this->getConf('licenseType');
1129        if ($licenseType !== 'none') {
1130            $html .= tpl_license($licenseType, $this->getConf('licenseImageOnly'), true, true);
1131        }
1132
1133        $html .= '</footer>';
1134
1135        if ($print === true) {
1136            echo $html;
1137        }
1138        return $html;
1139    }
1140
1141
1142    /**
1143     * Print or return breadcrumb trail
1144     *
1145     * @param   boolean $print Print out trail.
1146     * @param   boolean $parse Parse trail before printing.
1147     * @return  string         HTML string containing breadcrumbs
1148     */
1149    public function includeBreadcrumbs(bool $print = true, bool $parse = true)
1150    {
1151        global $conf, $ID, $lang, $ACT;
1152
1153        if (
1154            $this->getConf('breadcrumbHideHome') === true && strcasecmp($ID, 'start') === 0 &&
1155            strcasecmp($ACT, 'show') === 0 || strcasecmp($ACT, 'showtag') === 0
1156        ) {
1157            return '';
1158        }
1159
1160        $html = '<div class="mikio-breadcrumbs">';
1161        $html .= '<div class="mikio-container">';
1162        if (strcasecmp($ACT, 'show') === 0) {
1163            if ($conf['breadcrumbs'] === true) {
1164                if ($this->getConf('breadcrumbPrefix') === false && $this->getConf('breadcrumbSep') === false) {
1165                    ob_start();
1166                    tpl_breadcrumbs();
1167                    $html .= ob_get_contents();
1168                    ob_end_clean();
1169                } else {
1170                    $sep = '•';
1171                    $prefix = $lang['breadcrumb'];
1172
1173                    if ($this->getConf('breadcrumbSep') === true) {
1174                        $sep = $this->getConf('breadcrumbSepText');
1175                        $img = $this->getMediaFile('breadcrumb-sep', false);
1176
1177                        if ($img !== false) {
1178                            $sep = '<img src="' . $img . '">';
1179                        }
1180                    }
1181
1182                    if ($this->getConf('breadcrumbPrefix') === true) {
1183                        $prefix = $this->getConf('breadcrumbPrefixText');
1184                        $img = $this->getMediaFile('breadcrumb-prefix', false);
1185
1186                        if ($img !== false) {
1187                            $prefix = '<img src="' . $img . '">';
1188                        }
1189                    }
1190
1191                    $crumbs = breadcrumbs();
1192
1193                    $html .= '<ul>';
1194                    if (empty($prefix) === false) {
1195                        $html .= '<li class="prefix">' . $prefix . '</li>';
1196                    }
1197
1198                    $last = count($crumbs);
1199                    $i    = 0;
1200                    foreach ($crumbs as $id => $name) {
1201                        $i++;
1202                        $html .= '<li class="sep">' . $sep . '</li>';
1203                        $html .= '<li' . ($i === $last ? ' class="curid"' : '') . '>';
1204                        $html .= tpl_pagelink($id, null, true);
1205                        $html .= '</li>';
1206                    }
1207
1208                    $html .= '</ul>';
1209                }//end if
1210            }//end if
1211        }//end if
1212
1213        $html .= '</div>';
1214        $html .= '</div>';
1215
1216        if ($parse === true) {
1217            $html = $this->includeIcons($html);
1218        }
1219        if ($print === true) {
1220            echo $html;
1221        }
1222        return $html;
1223    }
1224
1225    /**
1226     * Print or return you are here trail
1227     *
1228     * @param   boolean $print Print out trail.
1229     * @param   boolean $parse Parse trail before printing.
1230     * @return  string         HTML string containing breadcrumbs
1231     */
1232    public function includeYouAreHere(bool $print = true, bool $parse = true)
1233    {
1234        global $conf, $ID, $lang, $ACT;
1235
1236        if (
1237            $this->getConf('youarehereHideHome') === true && strcasecmp($ID, 'start') === 0 &&
1238            strcasecmp($ACT, 'show') === 0 || strcasecmp($ACT, 'showtag') === 0
1239        ) {
1240            return '';
1241        }
1242
1243        $html = '<div class="mikio-youarehere">';
1244        $html .= '<div class="mikio-container">';
1245        if (strcasecmp($ACT, 'show') === 0) {
1246            if ($conf['youarehere'] === true) {
1247                if ($this->getConf('youareherePrefix') === false && $this->getConf('youarehereSep') === false) {
1248                    ob_start();
1249                    tpl_youarehere();
1250                    $html .= ob_get_contents();
1251                    ob_end_clean();
1252                } else {
1253                    $sep = ' » ';
1254                    $prefix = $lang['youarehere'];
1255
1256                    if ($this->getConf('youarehereSep') === true) {
1257                        $sep = $this->getConf('youarehereSepText');
1258                        $img = $this->getMediaFile('youarehere-sep', false);
1259
1260                        if ($img !== false) {
1261                            $sep = '<img src="' . $img . '">';
1262                        }
1263                    }
1264
1265                    if ($this->getConf('youareherePrefix') === true) {
1266                        $prefix = $this->getConf('youareherePrefixText');
1267                        $img = $this->getMediaFile('youarehere-prefix', false);
1268
1269                        if ($img !== false) {
1270                            $prefix = '<img src="' . $img . '">';
1271                        }
1272                    }
1273
1274                    $html .= '<ul>';
1275                    if (empty($prefix) === false) {
1276                        $html .= '<li class="prefix">' . $prefix . '</li>';
1277                    }
1278                    $html .= '<li>' . tpl_pagelink(':' . $conf['start'], null, true) . '</li>';
1279
1280                    $parts = explode(':', $ID);
1281                    $count = count($parts);
1282
1283                    $part = '';
1284                    for ($i = 0; $i < ($count - 1); $i++) {
1285                        $part .= $parts[$i] . ':';
1286                        $page = $part;
1287                        if ($page === $conf['start']) {
1288                            continue;
1289                        }
1290
1291                        $html .= '<li class="sep">' . $sep . '</li>';
1292                        $html .= '<li>' . tpl_pagelink($page, null, true) . '</li>';
1293                    }
1294
1295                    resolve_pageid('', $page, $exists);
1296                    if ((isset($page) === true && $page === $part . $parts[$i]) === false) {
1297                        $page = $part . $parts[$i];
1298                        if ($page !== $conf['start']) {
1299                            $html .= '<li class="sep">' . $sep . '</li>';
1300                            $html .= '<li>' . tpl_pagelink($page, null, true) . '</li>';
1301                        }
1302                    }
1303
1304                    $html .= '</ul>';
1305                }//end if
1306            }//end if
1307
1308            $showLast = $this->getConf('youarehereShowLast');
1309            if ($showLast !== 0) {
1310                preg_match_all('/(<li[^>]*>.+?<\/li>)/', $html, $matches);
1311                if (count($matches) > 0 && count($matches[0]) > (($showLast * 2) + 2)) {
1312                    $count = count($matches[0]);
1313                    $list = '';
1314
1315                    // Show Home
1316                    $list .= $matches[0][0] . $matches[0][1];
1317
1318                    $list .= '<li>...</li>';
1319                    for ($i = ($count - ($showLast * 2)); $i <= $count; $i++) {
1320                        $list .= $matches[0][$i];
1321                    }
1322
1323                    $html = preg_replace('/<ul>.*<\/ul>/', '<ul>' . $list . '</ul>', $html);
1324                }
1325            }
1326
1327            switch ($this->getConf('youarehereHome')) {
1328                case 'none':
1329                    $html = preg_replace('/<li[^>]*>.+?<\/li>/', '', $html, 2);
1330                    break;
1331                case 'home':
1332                    $html = preg_replace('/(<a[^>]*>)(.+?)(<\/a>)/', '$1' . tpl_getlang('home') . '$3', $html, 1);
1333                    break;
1334                case 'icon':
1335                    $html = preg_replace('/(<a[^>]*>)(.+?)(<\/a>)/', '$1' .
1336                        $this->mikioInlineIcon('home') . '$3', $html, 1);
1337                    break;
1338            }
1339        } else {
1340            $html .= '&#8810; ';
1341            if (isset($_GET['page']) === true) {
1342                $html .= '<a href="' . wl($ID, ['do' => $ACT]) . '">Back</a>&nbsp;&nbsp;&nbsp;/&nbsp;&nbsp;&nbsp;';
1343            }
1344            $html .= '<a href="' . wl($ID) . '">View Page</a>';
1345        }//end if
1346
1347        $html .= '</div>';
1348        $html .= '</div>';
1349
1350        if ($parse === true) {
1351            $html = $this->includeIcons($html);
1352        }
1353        if ($print === true) {
1354            echo $html;
1355        }
1356        return $html;
1357    }
1358
1359    /**
1360     * Get Page Title
1361     *
1362     * @return string page title
1363     */
1364    public function parsePageTitle()
1365    {
1366        global $ID;
1367
1368        $title = p_get_first_heading($ID);
1369        if (strlen($title) <= 0) {
1370            $title = tpl_pagetitle(null, true);
1371        }
1372        $title = $this->includeIcons($title);
1373
1374        return $title;
1375    }
1376
1377
1378    /**
1379     * Print or return hero block
1380     *
1381     * @param   boolean $print Print content.
1382     * @return  string         contents of hero
1383     */
1384    public function includeHero(bool $print = true)
1385    {
1386        $html = '';
1387
1388        if ($this->getConf('heroTitle') === true) {
1389            $html .= '<div class="mikio-hero">';
1390            $html .= '<div class="mikio-container">';
1391            $html .= '<div class="mikio-hero-text">';
1392            if (strcasecmp($this->getConf('youareherePosition'), 'hero') === 0) {
1393                $html .= $this->includeYouAreHere(false);
1394            }
1395            if (strcasecmp($this->getConf('breadcrumbPosition'), 'hero') === 0) {
1396                $html .= $this->includeBreadcrumbs(false);
1397            }
1398
1399            $html .= '<h1 class="mikio-hero-title">';
1400            $html .= $this->parsePageTitle();    // No idea why this requires a blank space afterwards to work?
1401            $html .= '</h1>';
1402            $html .= '<h2 class="mikio-hero-subtitle"></h2>';
1403            $html .= '</div>';
1404
1405            $hero_image = $this->getMediaFile('hero', true, $this->getConf('heroImagePropagation', true));
1406            $hero_image_resize_class = '';
1407            if (empty($hero_image) === false) {
1408                $hero_image = ' style="background-image:url(\'' . $hero_image . '\');"';
1409                $hero_image_resize_class = ' mikio-hero-image-resize';
1410            }
1411
1412            $html .= '<div class="mikio-hero-image' . $hero_image_resize_class . '"' . $hero_image .
1413                '><div class="mikio-tags"></div></div>';
1414
1415            $html .= '</div>';
1416            $html .= '</div>';
1417        }//end if
1418
1419        if ($print === true) {
1420            echo $html;
1421        }
1422
1423        return $html;
1424    }
1425
1426
1427    /**
1428     * Print or return out TOC
1429     *
1430     * @param   boolean $print Print TOC.
1431     * @param   boolean $parse Parse icons.
1432     * @return  string         contents of TOC
1433     */
1434    public function includeTOC(bool $print = true, bool $parse = true)
1435    {
1436        $html = '';
1437
1438        $tocHtml = tpl_toc(true);
1439
1440        if (empty($tocHtml) === false) {
1441            $tocHtml = preg_replace('/<li.*><div.*><a.*><\/a><\/div><\/li>\s*/', '', $tocHtml);
1442            $tocHtml = preg_replace('/<ul.*>\s*<\/ul>\s*/', '', $tocHtml);
1443
1444            $html .= '<div class="mikio-toc">';
1445            $html .= $tocHtml;
1446            $html .= '</div>';
1447        }
1448
1449        if ($parse === true) {
1450            $html = $this->includeIcons($html);
1451        }
1452
1453        if ($print === true) {
1454            echo $html;
1455        }
1456
1457        return $html;
1458    }
1459
1460
1461    /**
1462     * Parse the string and replace icon elements with included icon libraries
1463     *
1464     * @param   string $str Content to parse.
1465     * @return  string      parsed string
1466     */
1467    public function includeIcons(string $str)
1468    {
1469        global $ACT, $MIKIO_ICONS;
1470
1471        $iconTag = $this->getConf('iconTag', 'icon');
1472        if (empty($iconTag) === true) {
1473            return $str;
1474        }
1475
1476        if (
1477            in_array($ACT, ['show', 'showtag', 'revisions', 'index', 'preview']) === true ||
1478            strcasecmp($ACT, 'admin') === 0 && count($MIKIO_ICONS) > 0
1479        ) {
1480            $content = $str;
1481            $preview = null;
1482
1483            if (strcasecmp($ACT, 'preview') === 0) {
1484                $html = new \simple_html_dom();
1485                $html->stripRNAttrValues = false;
1486                $html->load($str, true, false);
1487
1488                $preview = $html->find('div.preview');
1489                if (is_array($preview) === true && count($preview) > 0) {
1490                    $content = $preview[0]->innertext;
1491                }
1492            }
1493
1494            $page_regex = '/(.*)/';
1495            if (stripos($str, '<pre') !== false) {
1496                $page_regex = '/<(?!pre|\/).*?>(.*)[^<]*/';
1497            }
1498
1499            $content = preg_replace_callback($page_regex, function ($icons) {
1500                $iconTag = $this->getConf('iconTag', 'icon');
1501
1502                return preg_replace_callback(
1503                    '/&lt;' . $iconTag . ' ([\w\- #]*)&gt;(?=[^>]*(<|$))/',
1504                    function ($matches) {
1505                        global $MIKIO_ICONS;
1506
1507                        $s = $matches[0];
1508
1509                        if (count($MIKIO_ICONS) > 0) {
1510                            $icon = $MIKIO_ICONS[0];
1511
1512                            if (count($matches) > 1) {
1513                                $e = explode(' ', $matches[1]);
1514
1515                                if (count($e) > 1) {
1516                                    foreach ($MIKIO_ICONS as $iconItem) {
1517                                        if (strcasecmp($iconItem['name'], $e[0]) === 0) {
1518                                            $icon = $iconItem;
1519
1520                                            $s = $icon['insert'];
1521                                            for ($i = 1; $i < 9; $i++) {
1522                                                if (count(empty($e) < $i || $e[$i]) === true) {
1523                                                    if (isset($icon['$' . $i]) === true) {
1524                                                        $s = str_replace('$' . $i, $icon['$' . $i], $s);
1525                                                    }
1526                                                } else {
1527                                                    $s = str_replace('$' . $i, $e[$i], $s);
1528                                                }
1529                                            }
1530
1531                                            $dir = '';
1532                                            if (isset($icon['dir']) === true) {
1533                                                $dir = $this->baseDir . 'icons/' . $icon['dir'] . '/';
1534                                            }
1535
1536                                            $s = str_replace('$0', $dir, $s);
1537
1538                                            break;
1539                                        }//end if
1540                                    }//end foreach
1541                                } else {
1542                                    $s = str_replace('$1', $matches[1], $icon['insert']);
1543                                }//end if
1544                            }//end if
1545                        }//end if
1546
1547                        $s = preg_replace('/(class=")(.*)"/', '$1mikio-icon $2"', $s, -1, $count);
1548                        if ($count === 0) {
1549                            $s = preg_replace('/(<\w* )/', '$1class="mikio-icon" ', $s);
1550                        }
1551
1552                        return $s;
1553                    },
1554                    $icons[0]
1555                );
1556            }, $content);
1557
1558            if (strcasecmp($ACT, 'preview') === 0) {
1559                if (is_array($preview) === true && count($preview) > 0) {
1560                    $preview[0]->innertext = $content;
1561                }
1562
1563                $str = $html->save();
1564                $html->clear();
1565                unset($html);
1566            } else {
1567                $str = $content;
1568            }
1569        }//end if
1570
1571        return $str;
1572    }
1573
1574    /**
1575     * Parse HTML for theme
1576     *
1577     * @param   string $content HTML content to parse.
1578     * @return  string          Parsed content
1579     */
1580    public function parseContent(string $content)
1581    {
1582        global $INPUT, $ACT;
1583
1584        // Add Mikio Section titles
1585        if (strcasecmp($INPUT->str('page'), 'config') === 0) {
1586            $admin_sections = [
1587                // Section      Insert Before                 Icon
1588                'navbar'        => ['navbarUseTitleIcon',      ''],
1589                'search'        => ['searchButton',            ''],
1590                'hero'          => ['heroTitle',               ''],
1591                'tags'          => ['tagsConsolidate',         ''],
1592                'breadcrumb'    => ['breadcrumbHideHome',      ''],
1593                'youarehere'    => ['youarehereHideHome',      ''],
1594                'sidebar'       => ['sidebarShowLeft',         ''],
1595                'toc'           => ['tocFull',                 ''],
1596                'pagetools'     => ['pageToolsFloating',       ''],
1597                'footer'        => ['footerCustomMenuText',    ''],
1598                'license'       => ['licenseType',             ''],
1599                'acl'           => ['includePageUseACL',       ''],
1600                'sticky'        => ['stickyTopHeader',         ''],
1601            ];
1602
1603            foreach ($admin_sections as $section => $items) {
1604                $search = $items[0];
1605                $icon   = $items[1];
1606
1607                $content = preg_replace(
1608                    '/<tr(.*)>\s*<td class="label">\s*<span class="outkey">(tpl»mikio»' . $search . ')<\/span>/',
1609                    '<tr$1><td class="mikio-config-table-header" colspan="2">' . $this->mikioInlineIcon($icon) .
1610                        tpl_getLang('config_' . $section) .
1611                        '</td></tr><tr class="default"><td class="label"><span class="outkey">tpl»mikio»' .
1612                        $search . '</span>',
1613                    $content
1614                );
1615            }
1616        }//end if
1617
1618        if (strcasecmp($ACT, 'admin') === 0 && isset($_GET['page']) === false) {
1619            $content = preg_replace('/(<ul.*?>.*?)<\/ul>.*?<ul.*?>(.*?<\/ul>)/s', '$1$2', $content);
1620        }
1621
1622        // Page Revisions - Table Fix
1623        if (strpos($content, 'id="page__revisions"') !== false) {
1624            $content = preg_replace(
1625                '/(<span class="sum">\s.*<\/span>\s.*<span class="user">\s.*<\/span>)/',
1626                '<span>$1</span>',
1627                $content
1628            );
1629        }
1630
1631        $html = new \simple_html_dom();
1632        $html->stripRNAttrValues = false;
1633        $html->load($content, true, false);
1634
1635        if ($html === false) {
1636            return $content;
1637        }
1638
1639        /* Buttons */
1640        foreach ($html->find('#config__manager button') as $node) {
1641            $c = explode(' ', $node->class);
1642            if (in_array('mikio-button', $c) === false) {
1643                $c[] = 'mikio-button';
1644            }
1645            $node->class = implode(' ', $c);
1646        }
1647
1648
1649        /* Buttons - Primary */
1650        foreach ($html->find('#config__manager [type=submit]') as $node) {
1651            $c = explode(' ', $node->class);
1652            if (in_array('mikio-primary', $c) === false) {
1653                $c[] = 'mikio-primary';
1654            }
1655            $node->class = implode(' ', $c);
1656        }
1657
1658        /* Hide page title if hero is enabled */
1659        if ($this->getConf('heroTitle') === true && $ACT !== 'preview') {
1660            $pageTitle = $this->parsePageTitle();
1661
1662            foreach ($html->find('h1,h2,h3,h4') as $elm) {
1663                if ($elm->innertext === $pageTitle) {
1664                    // $elm->innertext = '';
1665                    $elm->setAttribute('style', 'display:none');
1666
1667                    break;
1668                }
1669            }
1670        }
1671
1672        /* Hero subtitle */
1673        foreach ($html->find('p') as $elm) {
1674            $i = stripos($elm->innertext, '~~hero-subtitle');
1675            if ($i !== false) {
1676                $j = strpos($elm->innertext, '~~', ($i + 2));
1677                if ($j !== false) {
1678                    if ($j > ($i + 16)) {
1679                        $subtitle = substr($elm->innertext, ($i + 16), ($j - $i - 16));
1680                        $this->footerScript['hero-subtitle'] = 'mikio.setHeroSubTitle(\'' . $subtitle . '\')';
1681
1682                        // $elm->innertext = substr($elm->innertext, 0, $i + 2) . substr($elm->innertext, $j + 2);
1683                        $elm->innertext = preg_replace('/~~hero-subtitle (.+?)~~.*/ui', '', $elm->innertext);
1684                    }
1685
1686                    break;
1687                }
1688            }
1689        }
1690
1691        /* Hero image */
1692        foreach ($html->find('p') as $elm) {
1693            $image = '';
1694            preg_match('/~~hero-image (.+?)~~(?!.?")/ui', $elm->innertext, $matches);
1695            if (count($matches) > 0) {
1696                preg_match('/<img.*src="(.+?)"/ui', $matches[1], $imageTagMatches);
1697                if (count($imageTagMatches) > 0) {
1698                    $image = $imageTagMatches[1];
1699                } else {
1700                    preg_match('/<a.+?>(.+?)[~<]/ui', $matches[1], $imageTagMatches);
1701                    if (count($imageTagMatches) > 0) {
1702                        $image = $imageTagMatches[1];
1703                    } else {
1704                        $image = strip_tags($matches[1]);
1705                        if (stripos($image, ':') === false) {
1706                            $image = str_replace(['{', '}'], '', $image);
1707                            $i = stripos($image, '?');
1708                            if ($i !== false) {
1709                                $image = substr($image, 0, $i);
1710                            }
1711
1712                            $image = ml($image, '', true, '', false);
1713                        }
1714                    }
1715                }
1716
1717                $this->footerScript['hero-image'] = 'mikio.setHeroImage(\'' . $image . '\')';
1718
1719                $elm->innertext = preg_replace('/~~hero-image (.+?)~~.*/ui', '', $elm->innertext);
1720            }//end if
1721        }//end foreach
1722
1723        /* Hero colors - ~~hero-colors [background-color] [hero-title-color] [hero-subtitle-color]
1724        [breadcrumb-text-color] [breadcrumb-hover-color] (use 'initial' for original color) */
1725        foreach ($html->find('p') as $elm) {
1726            $i = stripos($elm->innertext, '~~hero-colors');
1727            if ($i !== false) {
1728                $j = strpos($elm->innertext, '~~', ($i + 2));
1729                if ($j !== false) {
1730                    if ($j > ($i + 14)) {
1731                        $color = substr($elm->innertext, ($i + 14), ($j - $i - 14));
1732                        $this->footerScript['hero-colors'] = 'mikio.setHeroColor(\'' . $color . '\')';
1733
1734                        $elm->innertext = preg_replace('/~~hero-colors (.+?)~~.*/ui', '', $elm->innertext);
1735                    }
1736
1737                    break;
1738                }
1739            }
1740        }
1741
1742        /* Hide parts - ~~hide-parts [parts]~~  */
1743        foreach ($html->find('p') as $elm) {
1744            $i = stripos($elm->innertext, '~~hide-parts');
1745            if ($i !== false) {
1746                $j = strpos($elm->innertext, '~~', ($i + 2));
1747                if ($j !== false) {
1748                    if ($j > ($i + 13)) {
1749                        $parts = explode(' ', substr($elm->innertext, ($i + 13), ($j - $i - 13)));
1750                        $script = '';
1751
1752                        foreach ($parts as $part) {
1753                            // $part = trim($part);
1754                            if (strlen($part) > 0) {
1755                                $script .= 'mikio.hidePart(\'' . $part . '\');';
1756                            }
1757                        }
1758
1759                        if (strlen($script) > 0) {
1760                            $this->footerScript['hide-parts'] = $script;
1761                        }
1762
1763                        $elm->innertext = preg_replace('/~~hide-parts (.+?)~~.*/ui', '', $elm->innertext);
1764                    }
1765
1766                    break;
1767                }//end if
1768            }//end if
1769        }//end foreach
1770
1771
1772        /* Page Tags (tag plugin) */
1773        if ($this->getConf('tagsConsolidate') === true) {
1774            $tags = '';
1775            foreach ($html->find('div.tags a') as $elm) {
1776                $tags .= $elm->outertext;
1777            }
1778
1779            foreach ($html->find('div.tags') as $elm) {
1780                $elm->innertext = '';
1781                $elm->setAttribute('style', 'display:none');
1782            }
1783
1784            if (empty($tags) === false) {
1785                $this->footerScript['tags'] = 'mikio.setTags(\'' . $tags . '\')';
1786            }
1787        }
1788
1789        // Configuration Manager
1790        if (strcasecmp($INPUT->str('page'), 'config') === 0) {
1791            // Additional save buttons
1792            foreach ($html->find('#config__manager') as $cm) {
1793                $saveButtons = '';
1794
1795                foreach ($cm->find('p') as $elm) {
1796                    $saveButtons = $elm->outertext;
1797                    $saveButtons = str_replace('<p>', '<p style="text-align:right">', $saveButtons);
1798                    $elm->outertext = '';
1799                }
1800
1801                foreach ($cm->find('fieldset') as $elm) {
1802                    $elm->innertext .= $saveButtons;
1803                }
1804            }
1805        }
1806
1807        $content = $html->save();
1808        $html->clear();
1809        unset($html);
1810
1811        return $content;
1812    }
1813
1814
1815    /**
1816     * Get DokuWiki namespace/page/URI as link
1817     *
1818     * @param   string $str String to parse.
1819     * @return  string      parsed URI
1820     */
1821    public function getLink(string $str)
1822    {
1823        $i = strpos($str, '://');
1824        if ($i !== false) {
1825            return $str;
1826        }
1827
1828        return wl($str);
1829    }
1830
1831
1832    /**
1833     * Check if the user can edit current namespace/page
1834     *
1835     * @return  boolean  user can edit
1836     */
1837    public function userCanEdit()
1838    {
1839        global $INFO;
1840        global $ID;
1841
1842        $wiki_file = wikiFN($ID);
1843        if (@file_exists($wiki_file) === false) {
1844            return true;
1845        }
1846        if ($INFO['isadmin'] === true || $INFO['ismanager'] === true) {
1847            return true;
1848        }
1849        // $meta_file = metaFN($ID, '.meta');
1850        if ($INFO['meta']['user'] === false) {
1851            return true;
1852        }
1853        if ($INFO['client'] === $INFO['meta']['user']) {
1854            return true;
1855        }
1856
1857        return false;
1858    }
1859
1860
1861    /**
1862     * Search for and return the uri of a media file
1863     *
1864     * @param string  $image           Image name to search for (without extension).
1865     * @param boolean $searchCurrentNS Search the current namespace.
1866     * @param boolean $propagate       Propagate search through the namespace.
1867     * @return string                  URI of the found media file
1868     */
1869    public function getMediaFile(string $image, bool $searchCurrentNS = true, bool $propagate = true)
1870    {
1871        global $INFO;
1872
1873        $ext = ['png', 'jpg', 'gif', 'svg'];
1874
1875        if ($searchCurrentNS === true) {
1876            $prefix[] = ':' . $INFO['namespace'] . ':';
1877        }
1878        if ($propagate === true) {
1879            $prefix[] = ':';
1880            $prefix[] = ':wiki:';
1881        }
1882        $theme = $this->getConf('customTheme');
1883        if (empty($theme) === false) {
1884            $prefix[] = 'themes/' . $theme . '/images/';
1885        }
1886        $prefix[] = 'images/';
1887
1888        $search = [];
1889        foreach ($prefix as $pitem) {
1890            foreach ($ext as $eitem) {
1891                $search[] = $pitem . $image . '.' . $eitem;
1892            }
1893        }
1894
1895        $img = '';
1896        $file = '';
1897        $url = '';
1898        $ismedia = false;
1899        $found = false;
1900
1901        foreach ($search as $img) {
1902            if (strcasecmp(substr($img, 0, 1), ':') === 0) {
1903                $file    = mediaFN($img);
1904                $ismedia = true;
1905            } else {
1906                $file    = tpl_incdir() . $img;
1907                $ismedia = false;
1908            }
1909
1910            if (file_exists($file) === true) {
1911                $found = true;
1912                break;
1913            }
1914        }
1915
1916        if ($found === false) {
1917            return false;
1918        }
1919
1920        if ($ismedia === true) {
1921            $url = ml($img, '', true, '', false);
1922        } else {
1923            $url = tpl_basedir() . $img;
1924        }
1925
1926        return $url;
1927    }
1928
1929
1930    /**
1931     * Print or return the page title
1932     *
1933     * @param string $page Page id or empty string for current page.
1934     * @return string      generated content
1935     */
1936    public function getPageTitle(string $page = '')
1937    {
1938        global $ID, $conf;
1939
1940        $html = '';
1941
1942        if (empty($page) === true) {
1943            $page = $ID;
1944        }
1945
1946        $html = p_get_first_heading($page);
1947        $html = strip_tags($html);
1948        $html = preg_replace('/\s+/', ' ', $html);
1949        $html .= ' [' . strip_tags($conf['title']) . ']';
1950        $html = trim($html);
1951
1952        return $html;
1953    }
1954
1955
1956    /**
1957     * Return inline theme icon
1958     *
1959     * @param   string $type Icon to retreive.
1960     * @return  string       HTML icon content
1961     */
1962    public function mikioInlineIcon(string $type)
1963    {
1964        switch ($type) {
1965            case 'wrench':
1966                return '<svg class="mikio-iicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 -256 1792 1792"
1967style="fill:currentColor"><g transform="matrix(1,0,0,-1,53.152542,1217.0847)"><path d="m 384,64 q 0,26 -19,45 -19,19
1968-45,19 -26,0 -45,-19 -19,-19 -19,-45 0,-26 19,-45 19,-19 45,-19 26,0 45,19 19,19 19,45 z m 644,420 -682,-682 q -37,-37
1969-90,-37 -52,0 -91,37 L 59,-90 Q 21,-54 21,0 21,53 59,91 L 740,772 Q 779,674 854.5,598.5 930,523 1028,484 z m 634,435 q
19700,-39 -23,-106 Q 1592,679 1474.5,595.5 1357,512 1216,512 1031,512 899.5,643.5 768,775 768,960 q 0,185 131.5,316.5 131.5,
1971131.5 316.5,131.5 58,0 121.5,-16.5 63.5,-16.5 107.5,-46.5 16,-11 16,-28 0,-17 -16,-28 L 1152,1120 V 896 l 193,-107 q 5,
19723 79,48.5 74,45.5 135.5,81 61.5,35.5 70.5,35.5 15,0 23.5,-10 8.5,-10 8.5,-25 z"/></g></svg>';
1973            case 'file':
1974                return '<svg class="mikio-iicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 -256 1792 1792"
1975style="fill:currentColor"><g transform="matrix(1,0,0,-1,235.38983,1277.8305)" id="g2991"><path d="M 128,0 H 1152 V 768
1976H 736 q -40,0 -68,28 -28,28 -28,68 v 416 H 128 V 0 z m 640,896 h 299 L 768,1195 V 896 z M 1280,768 V -32 q 0,-40 -28,
1977-68 -28,-28 -68,-28 H 96 q -40,0 -68,28 -28,28 -28,68 v 1344 q 0,40 28,68 28,28 68,28 h 544 q 40,0 88,-20 48,-20 76,-48
1978l 408,-408 q 28,-28 48,-76 20,-48 20,-88 z" id="path2993" inkscape:connector-curvature="0"
1979xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" /></g></svg>';
1980            case 'gear':
1981                return '<svg class="mikio-iicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 -256 1792 1792"
1982style="fill:currentColor"><g transform="matrix(1,0,0,-1,121.49153,1285.4237)" id="g3027"><path d="m 1024,640 q 0,106
1983-75,181 -75,75 -181,75 -106,0 -181,-75 -75,-75 -75,-181 0,-106 75,-181 75,-75 181,-75 106,0 181,75 75,75 75,181 z m
1984512,109 V 527 q 0,-12 -8,-23 -8,-11 -20,-13 l -185,-28 q -19,-54 -39,-91 35,-50 107,-138 10,-12 10,-25 0,-13 -9,-23 -27,
1985-37 -99,-108 -72,-71 -94,-71 -12,0 -26,9 l -138,108 q -44,-23 -91,-38 -16,-136 -29,-186 -7,-28 -36,-28 H 657 q -14,0
1986-24.5,8.5 Q 622,-111 621,-98 L 593,86 q -49,16 -90,37 L 362,16 Q 352,7 337,7 323,7 312,18 186,132 147,186 q -7,10 -7,23
19870,12 8,23 15,21 51,66.5 36,45.5 54,70.5 -27,50 -41,99 L 29,495 Q 16,497 8,507.5 0,518 0,531 v 222 q 0,12 8,23 8,11 19,
198813 l 186,28 q 14,46 39,92 -40,57 -107,138 -10,12 -10,24 0,10 9,23 26,36 98.5,107.5 72.5,71.5 94.5,71.5 13,0 26,-10 l
1989138,-107 q 44,23 91,38 16,136 29,186 7,28 36,28 h 222 q 14,0 24.5,-8.5 Q 914,1391 915,1378 l 28,-184 q 49,-16 90,-37 l
1990142,107 q 9,9 24,9 13,0 25,-10 129,-119 165,-170 7,-8 7,-22 0,-12 -8,-23 -15,-21 -51,-66.5 -36,-45.5 -54,-70.5 26,-50
199141,-98 l 183,-28 q 13,-2 21,-12.5 8,-10.5 8,-23.5 z" id="path3029" inkscape:connector-curvature="0" /></g></svg>';
1992            case 'user':
1993                return '<svg class="mikio-iicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 -256 1792 1792"
1994style="fill:currentColor"><g transform="matrix(1,0,0,-1,197.42373,1300.6102)"><path d="M 1408,131 Q 1408,11 1335,-58.5
19951262,-128 1141,-128 H 267 Q 146,-128 73,-58.5 0,11 0,131 0,184 3.5,234.5 7,285 17.5,343.5 28,402 44,452 q 16,50 43,97.5
199627,47.5 62,81 35,33.5 85.5,53.5 50.5,20 111.5,20 9,0 42,-21.5 33,-21.5 74.5,-48 41.5,-26.5 108,-48 Q 637,565 704,565 q
199767,0 133.5,21.5 66.5,21.5 108,48 41.5,26.5 74.5,48 33,21.5 42,21.5 61,0 111.5,-20 50.5,-20 85.5,-53.5 35,-33.5 62,-81
199827,-47.5 43,-97.5 16,-50 26.5,-108.5 10.5,-58.5 14,-109 Q 1408,184 1408,131 z m -320,893 Q 1088,865 975.5,752.5 863,640
1999704,640 545,640 432.5,752.5 320,865 320,1024 320,1183 432.5,1295.5 545,1408 704,1408 863,1408 975.5,1295.5 1088,1183
20001088,1024 z"/></g></svg>';
2001            case 'search':
2002                return '<svg class="mikio-iicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"
2003aria-hidden="true" style="fill:currentColor"><path d="M27 24.57l-5.647-5.648a8.895 8.895 0 0 0 1.522-4.984C22.875 9.01
200418.867 5 13.938 5 9.01 5 5 9.01 5 13.938c0 4.929 4.01 8.938 8.938 8.938a8.887 8.887 0 0 0 4.984-1.522L24.568 27 27
200524.57zm-13.062-4.445a6.194 6.194 0 0 1-6.188-6.188 6.195 6.195 0 0 1 6.188-6.188 6.195 6.195 0 0 1 6.188 6.188 6.195
20066.195 0 0 1-6.188 6.188z"/></svg>';
2007            case 'home':
2008                return '<svg class="mikio-iicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 -256 1792 1792"
2009aria-hidden="true" style="fill:currentColor"><g transform="matrix(1,0,0,-1,68.338983,1285.4237)" id="g3015">
2010<path d="M 1408,544 V 64 Q 1408,38 1389,19 1370,0 1344,0 H 960 V 384 H 704 V 0 H 320 q -26,0 -45,19 -19,19 -19,
201145 v 480 q 0,1 0.5,3 0.5,2 0.5,3 l 575,474 575,-474 q 1,-2 1,-6 z m 223,69 -62,-74 q -8,-9 -21,-11 h -3 q -13,
20120 -21,7 L 832,1112 140,535 q -12,-8 -24,-7 -13,2 -21,11 l -62,74 q -8,10 -7,23.5 1,13.5 11,21.5 l 719,
2013599 q 32,26 76,26 44,0 76,-26 l 244,-204 v 195 q 0,14 9,23 9,9 23,9 h 192 q 14,0 23,-9 9,-9 9,-23 V 840 l 219,
2014-182 q 10,-8 11,-21.5 1,-13.5 -7,-23.5 z" id="path3017" inkscape:connector-curvature="0"
2015xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" /></g></svg>';
2016        }//end switch
2017
2018        return '';
2019    }
2020
2021    /**
2022     * Finalize theme
2023     *
2024     * @return void
2025     */
2026    public function finalize()
2027    {
2028    }
2029
2030    /**
2031     * Show Messages
2032     *
2033     * @return void
2034     */
2035    public function showMessages()
2036    {
2037        global $ACT;
2038
2039        if ($this->lessIgnored === true) {
2040            msg(
2041                'useLESS is enabled on the Mikio template, however is not supported on this server',
2042                2,
2043                '',
2044                '',
2045                MSG_ADMINS_ONLY
2046            );
2047        }
2048
2049        $show = $this->getConf('showNotifications');
2050        if (
2051            strcasecmp($show, 'always') === 0 ||
2052            (strcasecmp($show, 'admin') === 0 && strcasecmp($ACT, 'admin') === 0)
2053        ) {
2054            global $MSG, $MSG_shown;
2055
2056            if (isset($MSG) === false) {
2057                return;
2058            }
2059
2060            if (isset($MSG_shown) === false) {
2061                $MSG_shown = [];
2062            }
2063
2064            foreach ($MSG as $msg) {
2065                $hash = md5($msg['msg']);
2066                if (isset($MSG_shown[$hash]) === true) {
2067                    continue;
2068                }
2069                // skip double messages
2070
2071                if (info_msg_allowed($msg) === true) {
2072                    echo '<div class="' . $msg['lvl'] . '">';
2073                    echo $msg['msg'];
2074                    echo '</div>';
2075                }
2076
2077                $MSG_shown[$hash] = true;
2078            }
2079
2080            unset($GLOBALS['MSG']);
2081        }//end if
2082    }
2083
2084    /**
2085     * Dokuwiki version
2086     *
2087     * @return  string        the dw version name
2088     */
2089    public function dwVersion()
2090    {
2091        if (function_exists('getVersionData') === true) {
2092            $version_data = getVersionData();
2093            if (is_array($version_data) === true && array_key_exists('date', $version_data) === true) {
2094                $version_items = explode(' ', $version_data['date']);
2095                if (count($version_items) >= 2) {
2096                    return preg_replace('/[^a-zA-Z0-9 ]+/', '', strtolower($version_items[1]));
2097                }
2098            }
2099        }
2100
2101        return 'unknown';
2102    }
2103
2104    /**
2105     * Dokuwiki version number
2106     *
2107     * @return  string        the dw version date converted to integer
2108     */
2109    public function dwVersionNumber()
2110    {
2111        if (function_exists('getVersionData') === true) {
2112            $version_data = getVersionData();
2113            if (is_array($version_data) === true && array_key_exists('date', $version_data) === true) {
2114                $version_items = explode(' ', $version_data['date']);
2115                if (count($version_items) >= 1) {
2116                    return intval(preg_replace('/[^0-9]+/', '', strtolower($version_items[0])));
2117                }
2118            }
2119        }
2120
2121        return 0;
2122    }
2123}
2124
2125global $TEMPLATE;
2126$TEMPLATE = \dokuwiki\template\mikio\Template::getInstance();
2127