* @license GPLv2 (http://www.gnu.org/licenses/gpl-2.0.html) */ namespace dokuwiki\template\mikio; use Doku_Event; use dokuwiki\Menu\PageMenu; use dokuwiki\Menu\SiteMenu; use dokuwiki\Menu\UserMenu; use ParensParser; use simple_html_dom; use DOMDocument; use DOMNode; if (defined('DOKU_INC') === false) { die(); } require_once('icons/icons.php'); require_once('inc/simple_html_dom.php'); require_once('inc/parens-parser.php'); class mikio { /** * @var mikio|null Instance of the class. */ private static $instance = null; /** * @var string Template directory path from local FS. */ public $tplDir = ''; /** * @var string Template directory path from web. */ public $baseDir = ''; /** * @var array Array of Javascript files to include in footer. */ public $footerScript = []; /** * @var string Notifications from included pages. */ private $includedPageNotifications = ''; /** * @var array Array of formatted template configuration values. */ static private $formattedConfigValues = []; /** * Class constructor */ public function __construct() { $this->tplDir = tpl_incdir(); $this->baseDir = tpl_basedir(); $this->registerHooks(); } /** * Returns the instance of the class * * @return self class instance */ public static function getInstance(): self { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * Register the themes hooks into Dokuwiki * * @return void */ private function registerHooks(): void { global $EVENT_HANDLER; $events_dispatcher = [ 'TPL_METAHEADER_OUTPUT' => 'metaheadersHandler' ]; foreach ($events_dispatcher as $event => $method) { $EVENT_HANDLER->register_hook($event, 'BEFORE', $this, $method); } } /** * Meta handler hook for DokuWiki * * @param Doku_Event $event DokuWiki Event. * @return void */ public function metaHeadersHandler(Doku_Event $event): void { global $MIKIO_ICONS; global $conf; global $MIKIO_TEMPLATE; $MIKIO_TEMPLATE = '123'; // TODO - is this set correctly? $this->includePage('theme', false); $stylesheets = []; $scripts = []; if (empty($this->getConf('customTheme')) === false) { if (file_exists($this->tplDir . 'themes/' . $this->getConf('customTheme') . '/style.less') === true) { $stylesheets[] = $this->baseDir . 'themes/' . $this->getConf('customTheme') . '/style.less'; } else { if (file_exists($this->tplDir . 'themes/' . $this->getConf('customTheme') . '/style.css') === true) { $stylesheets[] = $this->baseDir . 'themes/' . $this->getConf('customTheme') . '/style.css'; } } if (file_exists($this->tplDir . 'themes/' . $this->getConf('customTheme') . '/script.js') === true) { $scripts[] = $this->baseDir . 'themes/' . $this->getConf('customTheme') . '/script.js'; } } if (is_array($MIKIO_ICONS) === true && empty($this->getConf('iconTag', 'icon')) === false) { $icons = []; foreach ($MIKIO_ICONS as $icon) { if (isset($icon['name']) === true && isset($icon['css']) === true && isset($icon['insert']) === true) { $icons[] = $icon; if (empty($icon['css']) === false) { if (strpos($icon['css'], '//') === false) { $stylesheets[] = $this->baseDir . 'icons/' . $icon['css']; } else { $stylesheets[] = $icon['css']; } } } } $MIKIO_ICONS = $icons; } else { $MIKIO_ICONS = []; } $scripts[] = $this->baseDir . 'assets/mikio-typeahead.js'; $scripts[] = $this->baseDir . 'assets/mikio.js'; if ($this->getConf('useLESS') === true) { $stylesheets[] = $this->baseDir . 'assets/mikio.less'; } else { $stylesheets[] = $this->baseDir . 'assets/mikio.css'; } /* MikioPlugin Support */ if (plugin_load('action', 'mikioplugin') !== null) { if ($this->getConf('useLESS') === true) { $stylesheets[] = $this->baseDir . 'assets/mikioplugin.less'; } else { $stylesheets[] = $this->baseDir . 'assets/mikioplugin.css'; } } $set = []; foreach ($stylesheets as $style) { if (in_array($style, $set, true) === false) { if ($this->getConf('useLESS') === true && strcasecmp(substr($style, -5), '.less') === 0) { $style = $this->baseDir . 'css.php?css=' . str_replace($this->baseDir, '', $style); } array_unshift($event->data['link'], [ 'type' => 'text/css', 'rel' => 'stylesheet', 'href' => $style ]); } $set[] = $style; } $set = []; foreach ($scripts as $script) { if (in_array($script, $set, true) === false) { $script_params = [ 'type' => 'text/javascript', '_data' => '', 'src' => $script ]; // equal to or greator than hogfather if ($this->getDokuWikiVersion() >= 20200729 || $this->getDokuWikiVersion() === 0) { // greator than hogfather - defer always on if ($this->getDokuWikiVersion() >= 20200729 || $this->getDokuWikiVersion() === 0) { $script_params += ['defer' => 'defer']; } else { // hogfather - defer always on unless $conf['defer_js'] is false if (array_key_exists('defer_js', $conf) === false || $conf['defer_js'] === true) { $script_params += ['defer' => 'defer']; } } } $event->data['script'][] = $script_params; }//end if $set[] = $script; }//end foreach } /** * Print or return the footer metadata * * @param boolean $print Print the data to buffer. * @return string HTML footer meta data */ public function includeFooterMeta(bool $print = true): string { $html = ''; if (count($this->footerScript) > 0) { $html .= ''; } if ($print === true) { echo $html; } return $html; } /** * Retreive and parse theme configuration options * * @param string $key The configuration key to retreive. * @param mixed $default If key doesn't exist, return this value. * @return mixed parsed value of configuration */ public function getConf(string $key, $default = false) { if(array_key_exists($key, self::$formattedConfigValues) === true) { return self::$formattedConfigValues[$key]; } $value = tpl_getConf($key, $default); $data = [ ['keys' => ['navbarDWMenuType'], 'type' => 'choice', 'values' => ['both', 'icons', 'text'] ], ['keys' => ['navbarDWMenuCombine'], 'type' => 'choice', 'values' => ['combine', 'separate', 'dropdown'] ], ['keys' => ['navbarPosLeft', 'navbarPosMiddle', 'navbarPosRight'], 'type' => 'choice', 'values' => ['none', 'custom', 'search', 'dokuwiki'], 'default' => [ 'navbarPosLeft' => 'none', 'navbarPosMiddle' => 'search', 'navbarPosRight' => 'dokuwiki' ] ], ['keys' => ['navbarItemShowCreate', 'navbarItemShowShow', 'navbarItemShowRevs', 'navbarItemShowBacklink', 'navbarItemShowRecent', 'navbarItemShowMedia', 'navbarItemShowIndex', 'navbarItemShowProfile', 'navbarItemShowAdmin' ], 'type' => 'choice', 'values' => ['always', 'logged in', 'logged out', 'never'] ], ['keys' => ['navbarItemShowLogin', 'navbarItemShowLogout'], 'type' => 'choice', 'values' => ['always', 'never'] ], ['keys' => ['searchButton'], 'type' => 'choice', 'values' => ['icon', 'text'] ], ['keys' => ['breadcrumbPosition', 'youareherePosition'], 'type' => 'choice', 'values' => ['top', 'hero', 'page', 'none'] ], ['keys' => ['youarehereHome'], 'type' => 'choice', 'values' => [tpl_getLang('value_page_title'), 'home', 'icon', 'none'] ], ['keys' => ['sidebarLeftRow1', 'sidebarLeftRow2', 'sidebarLeftRow3', 'sidebarLeftRow4'], 'type' => 'choice', 'values' => ['none', tpl_getLang('value_logged_in_user'), 'search', 'content', 'tags'], 'default' => [ 'sidebarLeftRow1' => tpl_getLang('value_logged_in_user'), 'sidebarLeftRow2' => 'search', 'sidebarLeftRow3' => 'content' ] ], ['keys' => ['pageToolsFloating', 'pageToolsFooter'], 'type' => 'choice', 'values' => ['always', 'none', tpl_getLang('value_page_editors')] ], ['keys' => ['pageToolsShowCreate', 'pageToolsShowEdit', 'pageToolsShowRevs', 'pageToolsShowBacklink', 'pageToolsShowTop' ], 'type' => 'choice', 'values' => ['always', 'logged in', 'logged out', 'never'] ], ['keys' => ['showNotifications'], 'type' => 'choice', 'values' => ['admin', 'always', 'none', '', 'never'] ], ['keys' => ['licenseType'], 'type' => 'choice', 'values' => ['badge', 'button', 'none'] ], ['keys' => ['navbarUseTitleIcon'], 'type' => 'bool'], ['keys' => ['navbarUseTitleText'], 'type' => 'bool'], ['keys' => ['navbarUseTaglineText'], 'type' => 'bool'], ['keys' => ['navbarShowSub'], 'type' => 'bool'], ['keys' => ['heroTitle'], 'type' => 'bool'], ['keys' => ['heroImagePropagation'], 'type' => 'bool'], ['keys' => ['breadcrumbPrefix'], 'type' => 'bool'], ['keys' => ['breadcrumbSep'], 'type' => 'bool'], ['keys' => ['youareherePrefix'], 'type' => 'bool'], ['keys' => ['youarehereSep'], 'type' => 'bool'], ['keys' => ['sidebarShowLeft'], 'type' => 'bool'], ['keys' => ['sidebarShowRight'], 'type' => 'bool'], ['keys' => ['tocFull'], 'type' => 'bool'], ['keys' => ['footerSearch'], 'type' => 'bool'], ['keys' => ['licenseImageOnly'], 'type' => 'bool'], ['keys' => ['includePageUseACL'], 'type' => 'bool'], ['keys' => ['includePagePropagate'], 'type' => 'bool'], ['keys' => ['youarehereHideHome'], 'type' => 'bool'], ['keys' => ['tagsConsolidate'], 'type' => 'bool'], ['keys' => ['tagsShowHero'], 'type' => 'bool'], ['keys' => ['footerInPage'], 'type' => 'bool'], ['keys' => ['sidebarMobileDefaultCollapse'], 'type' => 'bool'], ['keys' => ['sidebarAlwaysShowLeft'], 'type' => 'bool'], ['keys' => ['sidebarAlwaysShowRight'], 'type' => 'bool'], ['keys' => ['searchUseTypeahead'], 'type' => 'bool'], ['keys' => ['showLightDark'], 'type' => 'bool'], ['keys' => ['autoLightDark'], 'type' => 'bool'], ['keys' => ['defaultDark'], 'type' => 'bool'], ['keys' => ['youarehereShowLast'], 'type' => 'int'], ['keys' => ['iconTag'], 'type' => 'string'], ['keys' => ['customTheme'], 'type' => 'string'], ['keys' => ['navbarCustomMenuText'], 'type' => 'string'], ['keys' => ['breadcrumbPrefixText'], 'type' => 'string'], ['keys' => ['breadcrumbSepText'], 'type' => 'string'], ['keys' => ['youareherePrefixText'], 'type' => 'string'], ['keys' => ['youarehereSepText'], 'type' => 'string'], ['keys' => ['footerPageInfoText'], 'type' => 'string'], ['keys' => ['footerCustomMenuText'], 'type' => 'string'], ['keys' => ['brandURLGuest'], 'type' => 'string'], ['keys' => ['brandURLUser'], 'type' => 'string'], ['keys' => ['useLESS'], 'type' => 'bool'], ['keys' => ['stickyTopHeader'], 'type' => 'bool'], ['keys' => ['stickyNavbar'], 'type' => 'bool'], ['keys' => ['stickyHeader'], 'type' => 'bool'], ['keys' => ['stickyLeftSidebar'], 'type' => 'bool'], ]; foreach ($data as $row) { // does not check case.... if (in_array($key, $row['keys'], true) === true) { if (array_key_exists('type', $row) === true) { switch ($row['type']) { case 'bool': return (bool) $value; case 'int': return (int) $value; case 'string': return $value; }//end switch }//end if if (in_array($value, $row['values'], true) === true) { return $value; } if (array_key_exists('default', $row) === true) { if (is_array($row['default']) === true) { if (array_key_exists($key, $row['default']) === true) { return $row['default'][$key]; } } else { return $row['default']; } } return reset($row['values']); }//end if }//end foreach self::$formattedConfigValues[$key] = $value; return $value; } /** * Check if a page exist in directory or namespace * * @param string $page Page/namespace to search. * @return boolean if page exists */ public function pageExists(string $page): bool { ob_start(); tpl_includeFile($page . '.html'); $html = ob_get_clean(); if (empty($html) === false) { return true; } $useACL = $this->getConf('includePageUseACL'); $propagate = $this->getConf('includePagePropagate'); if ($propagate === true) { if (page_findnearest($page, $useACL) !== false) { return true; } } elseif ($useACL === true && auth_quickaclcheck($page) !== AUTH_NONE) { return true; } return false; } /** * Print or return page from directory or namespace * * @param string $page Page/namespace to include. * @param boolean $print Print content. * @param boolean $parse Parse content before printing/returning. * @param string $classWrapper Wrap page in a div with class. * @return string contents of page found */ public function includePage(string $page, bool $print = true, bool $parse = true, string $classWrapper = ''): string { ob_start(); tpl_includeFile($page . '.html'); $html = ob_get_clean(); if (empty($html) === true) { $useACL = $this->getConf('includePageUseACL'); $propagate = $this->getConf('includePagePropagate'); ob_start(); $html = tpl_include_page($page, false, $propagate, $useACL); $this->includedPageNotifications .= ob_get_clean(); } if (empty($html) === false && $parse === true) { $html = $this->parseContent($html); // TODO - move to end of main.php } if (empty($classWrapper) === false && empty($html) === false) { $html = '
(.*)[^<]*/';
}
$content = preg_replace_callback($page_regex, function ($icons) {
$iconTag = $this->getConf('iconTag', 'icon');
return preg_replace_callback(
'/<' . $iconTag . ' ([\w\- #]*)>(?=[^>]*(<|$))/',
function ($matches) {
global $MIKIO_ICONS;
$s = $matches[0];
if (count($MIKIO_ICONS) > 0) {
$icon = $MIKIO_ICONS[0];
if (count($matches) > 1) {
$e = explode(' ', $matches[1]);
if (count($e) > 1) {
foreach ($MIKIO_ICONS as $iconItem) {
if (strcasecmp($iconItem['name'], $e[0]) === 0) {
$icon = $iconItem;
$s = $icon['insert'];
for ($i = 1; $i < 9; $i++) {
if (count($e) < $i || empty($e[$i]) === true) {
if (isset($icon['$' . $i]) === true) {
$s = str_replace('$' . $i, $icon['$' . $i], $s);
}
} else {
$s = str_replace('$' . $i, $e[$i], $s);
}
}
$dir = '';
if (isset($icon['dir']) === true) {
$dir = $this->baseDir . 'icons/' . $icon['dir'] . '/';
}
$s = str_replace('$0', $dir, $s);
break;
}//end if
}//end foreach
} else {
$s = str_replace('$1', $matches[1], $icon['insert']);
}//end if
}//end if
}//end if
$s = preg_replace('/(class=")(.*)"/', '$1mikio-icon $2"', $s, -1, $count);
if ($count === 0) {
$s = preg_replace('/(<\w* )/', '$1class="mikio-icon" ', $s);
}
return $s;
},
$icons[0]
);
}, $content);
if (strcasecmp($ACT, 'preview') === 0) {
if (is_array($preview) === true && count($preview) > 0) {
$preview[0]->innertext = $content;
}
$str = $html->save();
$html->clear();
unset($html);
} else {
$str = $content;
}
}//end if
return $str;
}
/**
* Parse HTML for theme
*
* @param string $content HTML content to parse.
* @return string Parsed content
*/
public function parseContent(string $content): string
{
global $INPUT, $ACT;
// Add Mikio Section titles
if (strcasecmp($INPUT->str('page'), 'config') === 0) {
$admin_sections = [
// Section Insert Before Icon
'navbar' => ['navbarUseTitleIcon', ''],
'search' => ['searchButton', ''],
'hero' => ['heroTitle', ''],
'tags' => ['tagsConsolidate', ''],
'breadcrumb' => ['breadcrumbHideHome', ''],
'youarehere' => ['youarehereHideHome', ''],
'sidebar' => ['sidebarShowLeft', ''],
'toc' => ['tocFull', ''],
'pagetools' => ['pageToolsFloating', ''],
'footer' => ['footerPageInfoText', ''],
'license' => ['licenseType', ''],
'acl' => ['includePageUseACL', ''],
'sticky' => ['stickyTopHeader', ''],
];
foreach ($admin_sections as $section => $items) {
$search = $items[0];
$icon = $items[1];
$content = preg_replace(
'/\s*\s*(tpl»mikio»' . $search . ')<\/span>/',
'' . $this->mikioInlineIcon($icon) .
tpl_getLang('config_' . $section) .
' tpl»mikio»' .
$search . '',
$content
);
}
} elseif (strcasecmp($INPUT->str('page'), 'styling') === 0) {
$mikioPluginMissing = true;
/* Hide plugin fields if not installed */
if (plugin_load('action', 'mikioplugin') !== null) {
$mikioPluginMissing = false;
}
$style_headers = [
['title' => tpl_getLang('style_header_base'), 'starts_with' => '__text_'],
['title' => tpl_getLang('style_header_code'), 'starts_with' => '__code_'],
['title' => tpl_getLang('style_header_controls'), 'starts_with' => '__control_'],
['title' => tpl_getLang('style_header_header'), 'starts_with' => '__topheader_'],
['title' => tpl_getLang('style_header_navbar'), 'starts_with' => '__navbar_'],
['title' => tpl_getLang('style_header_sub_navbar'), 'starts_with' => '__subnavbar_'],
['title' => tpl_getLang('style_header_tags'), 'starts_with' => '__tag_background_color_'],
['title' => tpl_getLang('style_header_breadcrumbs'), 'starts_with' => '__breadcrumb_'],
['title' => tpl_getLang('style_header_hero'), 'starts_with' => '__hero_'],
['title' => tpl_getLang('style_header_sidebar'), 'starts_with' => '__sidebar_'],
['title' => tpl_getLang('style_header_content'), 'starts_with' => '__content_'],
['title' => tpl_getLang('style_header_toc'), 'starts_with' => '__toc_'],
['title' => tpl_getLang('style_header_page_tools'), 'starts_with' => '__pagetools_'],
['title' => tpl_getLang('style_header_footer'), 'starts_with' => '__footer_'],
['title' => tpl_getLang('style_header_table'), 'starts_with' => '__table_'],
['title' => tpl_getLang('style_header_dropdown'), 'starts_with' => '__dropdown_'],
['title' => tpl_getLang('style_header_section_edit'), 'starts_with' => '__section_edit_'],
['title' => tpl_getLang('style_header_tree'), 'starts_with' => '__tree_'],
['title' => tpl_getLang('style_header_tabs'), 'starts_with' => '__tab_'],
['title' => tpl_getLang('style_header_mikio_plugin'), 'starts_with' => '__plugin_', 'heading' => 'h2',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_primary_colours'), 'starts_with' => '__plugin_primary_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_secondary_colours'), 'starts_with' => '__plugin_secondary_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_success_colours'), 'starts_with' => '__plugin_success_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_danger_colours'), 'starts_with' => '__plugin_danger_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_warning_colours'), 'starts_with' => '__plugin_warning_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_info_colours'), 'starts_with' => '__plugin_info_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_light_colours'), 'starts_with' => '__plugin_light_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_dark_colours'), 'starts_with' => '__plugin_dark_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_link_colours'), 'starts_with' => '__plugin_link_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_carousel'), 'starts_with' => '__plugin_carousel_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_steps'), 'starts_with' => '__plugin_steps_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_tabgroup'), 'starts_with' => '__plugin_tabgroup_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_tooltip'), 'starts_with' => '__plugin_tooltip_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_dark_mode'), 'starts_with' => '__darkmode_', 'heading' => 'h2'],
['title' => tpl_getLang('style_header_dark_mode_base'), 'starts_with' => '__darkmode_text_'],
['title' => tpl_getLang('style_header_dark_mode_code'), 'starts_with' => '__darkmode_code_'],
['title' => tpl_getLang('style_header_dark_mode_controls'), 'starts_with' => '__darkmode_control_'],
['title' => tpl_getLang('style_header_dark_mode_header'), 'starts_with' => '__darkmode_topheader_'],
['title' => tpl_getLang('style_header_dark_mode_navbar'), 'starts_with' => '__darkmode_navbar_'],
['title' => tpl_getLang('style_header_dark_mode_sub_navbar'), 'starts_with' => '__darkmode_subnavbar_'],
['title' => tpl_getLang('style_header_dark_mode_tags'), 'starts_with' => '__darkmode_tag_background_color_'],
['title' => tpl_getLang('style_header_dark_mode_breadcrumbs'), 'starts_with' => '__darkmode_breadcrumb_'],
['title' => tpl_getLang('style_header_dark_mode_hero'), 'starts_with' => '__darkmode_hero_'],
['title' => tpl_getLang('style_header_dark_mode_sidebar'), 'starts_with' => '__darkmode_sidebar_'],
['title' => tpl_getLang('style_header_dark_mode_content'), 'starts_with' => '__darkmode_content_'],
['title' => tpl_getLang('style_header_dark_mode_toc'), 'starts_with' => '__darkmode_toc_'],
['title' => tpl_getLang('style_header_dark_mode_page_tools'), 'starts_with' => '__darkmode_pagetools_'],
['title' => tpl_getLang('style_header_dark_mode_footer'), 'starts_with' => '__darkmode_footer_'],
['title' => tpl_getLang('style_header_dark_mode_table'), 'starts_with' => '__darkmode_table_'],
['title' => tpl_getLang('style_header_dark_mode_dropdown'), 'starts_with' => '__darkmode_dropdown_'],
['title' => tpl_getLang('style_header_dark_mode_section_edit'), 'starts_with' => '__darkmode_section_edit_'],
['title' => tpl_getLang('style_header_dark_mode_tree'), 'starts_with' => '__darkmode_tree_'],
['title' => tpl_getLang('style_header_dark_mode_tabs'), 'starts_with' => '__darkmode_tab_'],
['title' => tpl_getLang('style_header_mikio_plugin_dark_mode'), 'starts_with' => '__plugin_darkmode_', 'heading' => 'h2',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_primary_colours'), 'starts_with' => '__plugin_darkmode_primary_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_secondary_colours'), 'starts_with' => '__plugin_darkmode_secondary_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_success_colours'), 'starts_with' => '__plugin_darkmode_success_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_danger_colours'), 'starts_with' => '__plugin_darkmode_danger_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_warning_colours'), 'starts_with' => '__plugin_darkmode_warning_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_info_colours'), 'starts_with' => '__plugin_darkmode_info_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_light_colours'), 'starts_with' => '__plugin_darkmode_light_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_dark_colours'), 'starts_with' => '__plugin_darkmode_dark_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_link_colours'), 'starts_with' => '__plugin_darkmode_link_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_carousel'), 'starts_with' => '__plugin_darkmode_carousel_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_steps'), 'starts_with' => '__plugin_darkmode_steps_', 'hidden' => $mikioPluginMissing],
['title' => tpl_getLang('style_header_dark_mode_tabgroup'), 'starts_with' => '__plugin_darkmode_tabgroup_',
'hidden' => $mikioPluginMissing
],
['title' => tpl_getLang('style_header_dark_mode_tooltip'), 'starts_with' => '__plugin_darkmode_tooltip_', 'hidden' => $mikioPluginMissing],
];
foreach ($style_headers as $header) {
if (array_key_exists('heading', $header) === false) {
$header['heading'] = 'h3';
}
if (array_key_exists('hidden', $header) === false) {
$header['hidden'] = false;
}
$content = preg_replace(
'/( \s*\s*