* @license GPLv2 (http://www.gnu.org/licenses/gpl-2.0.html)
*/
namespace dokuwiki\template\mikio;
if (defined('DOKU_INC') === false) {
die();
}
require_once('icons/icons.php');
require_once('inc/simple_html_dom.php');
class Template
{
/**
* @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 boolean Ignore LESS files.
*/
public $lessIgnored = false;
/**
* Class constructor
*/
public function __construct()
{
$this->tplDir = tpl_incdir();
$this->baseDir = tpl_basedir();
$this->registerHooks();
}
/**
* Returns the instance of the class
*
* @return Template class instance
*/
public static function getInstance()
{
static $instance = null;
if (empty($instance) === true) {
$instance = new Template();
}
return $instance;
}
/**
* Register the themes hooks into Dokuwiki
*
* @return void
*/
private function registerHooks()
{
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)
{
global $MIKIO_ICONS;
global $conf;
$this->includePage('theme', false, true);
$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';
}
$set = [];
foreach ($stylesheets as $style) {
if (in_array($style, $set) === false) {
if (strcasecmp(substr($style, -5), '.less') === 0 && $this->getConf('useLESS') === true) {
$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) === false) {
$script_params = [
'type' => 'text/javascript',
'_data' => '',
'src' => $script
];
// equal to or greator than hogfather
if ($this->dwVersionNumber() >= 20200729) {
// greator than hogfather - defer always on
if ($this->dwVersionNumber() >= 20200729) {
$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 meta data
*
* @param boolean $print Print the data to buffer.
* @return string HTML footer meta data
*/
public function includeFooterMeta(bool $print = true)
{
$html = '';
if (count($this->footerScript) > 0) {
$html .= '';
}
if ($print === true) {
echo $html;
}
return $html;
}
// phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
/**
* 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)
{
$value = tpl_getConf($key, $default);
$data = [
['keys' => ['navbarDWMenuType'], 'type' => 'choice',
'values' => ['both', 'icons', 'text']
],
['keys' => ['navbarDWMenuCombine'], 'type' => 'choice',
'values' => ['combine', 'seperate', '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' => ['page title', 'home', 'icon', 'none']
],
['keys' => ['sidebarLeftRow1', 'sidebarLeftRow2', 'sidebarLeftRow3', 'sidebarLeftRow4'],
'type' => 'choice',
'values' => ['none', 'logged in user', 'search', 'content', 'tags'],
'default' => [
'sidebarLeftRow1' => 'logged in user',
'sidebarLeftRow2' => 'search',
'sidebarLeftRow3' => 'content'
]
],
['keys' => ['pageToolsFloating', 'pageToolsFooter'],
'type' => 'choice',
'values' => ['always', 'none', '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']
],
['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' => ['footerInPage'], 'type' => 'bool'],
['keys' => ['sidebarMobileDefaultCollapse'], 'type' => 'bool'],
['keys' => ['sidebarAlwaysShowLeft'], 'type' => 'bool'],
['keys' => ['sidebarAlwaysShowRight'], 'type' => 'bool'],
['keys' => ['searchUseTypeahead'], 'type' => 'bool'],
['keys' => ['showLightDark'], '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' => ['footerCustomMenuText'], 'type' => 'string'],
['keys' => ['brandURLGuest'], 'type' => 'string'],
['keys' => ['brandURLUser'], 'type' => 'string'],
['keys' => ['useLESS'], 'type' => 'less'],
];
foreach ($data as $row) {
// does not check case....
if (in_array($key, $row['keys']) === 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;
case 'less':
$value = (bool) $value;
$lessAvailable = true;
// check for less library
$lesscLib = '../../../vendor/marcusschwarz/lesserphp/lessc.inc.php';
if (file_exists($lesscLib) === false) {
$lesscLib = $_SERVER['DOCUMENT_ROOT'] . '/vendor/marcusschwarz/lesserphp/lessc.inc.php';
}
if (file_exists($lesscLib) === false) {
$lesscLib = '../../../../../app/dokuwiki/vendor/marcusschwarz/lesserphp/lessc.inc.php';
}
if (file_exists($lesscLib) === false) {
$lesscLib = $_SERVER['DOCUMENT_ROOT'] .
'/app/dokuwiki/vendor/marcusschwarz/lesserphp/lessc.inc.php';
}
if (file_exists($lesscLib) === false) {
$lessAvailable = false;
}
// check for ctype extensions
if (function_exists('ctype_digit') === false) {
$lessAvailable = false;
}
if ($value === true && $lessAvailable === false) {
$this->lessIgnored = true;
$value = false;
}
return $value;
}//end switch
}//end if
if (in_array($value, $row['values']) === 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
return $value;
}
// phpcs:enable
/**
* 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)
{
ob_start();
tpl_includeFile($page . '.html');
$html = ob_get_contents();
ob_end_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 = '')
{
ob_start();
tpl_includeFile($page . '.html');
$html = ob_get_contents();
ob_end_clean();
if (empty($html) === true) {
$useACL = $this->getConf('includePageUseACL');
$propagate = $this->getConf('includePagePropagate');
$html = '';
$html = tpl_include_page($page, false, $propagate, $useACL);
}
if (empty($html) === false && $parse === true) {
$html = $this->parseContent($html);
}
if (empty($classWrapper) === false && empty($html) === false) {
$html = '
' . $html . '
';
}
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Print or return logged in user information
*
* @param boolean $print Print content.
* @return string user information
*/
public function includeLoggedIn(bool $print = true)
{
$html = '';
if (empty($_SERVER['REMOTE_USER']) === false) {
$html .= '';
ob_start();
tpl_userinfo();
$html .= ob_get_contents();
ob_end_clean();
$html .= '
';
}
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Print or return DokuWiki Menu
*
* @param boolean $print Print content.
* @return string contents of the menu
*/
public function includeDWMenu(bool $print = true)
{
global $lang;
global $USERINFO;
$loggedIn = (is_array($USERINFO) === true && count($USERINFO) > 0);
$html = '';
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Create a nav element from a string. |;
*
* @param string $str String to generate nav.
* @return string nav elements generated
*/
public function stringToNav(string $str)
{
$html = '';
if (empty($str) === false) {
$items = explode(';', $str);
if (count($items) > 0) {
$html .= '';
}
}
return $html;
}
/**
* print or return the main navbar
*
* @param boolean $print Print the navbar.
* @param boolean $showSub Include the sub navbar.
* @return string generated content
*/
public function includeNavbar(bool $print = true, bool $showSub = false)
{
global $conf, $USERINFO;
$homeUrl = wl();
if (plugin_isdisabled('showpageafterlogin') === false) {
$p = &plugin_load('action', 'showpageafterlogin');
if (empty($p) === false) {
if (is_array($USERINFO) === true && count($USERINFO) > 0) {
$homeUrl = wl($p->getConf('page_after_login'));
}
}
} else {
if (is_array($USERINFO) === true && count($USERINFO) > 0) {
$url = $this->getConf('brandURLUser');
if (strlen($url) > 0) {
$homeUrl = $url;
}
} else {
$url = $this->getConf('brandURLGuest');
if (strlen($url) > 0) {
$homeUrl = $url;
}
}
}
$html = '';
$html .= '';
$html .= '';
$html .= '
';
if ($this->getConf('navbarUseTitleIcon') === true || $this->getConf('navbarUseTitleText') === true) {
// Brand image
if ($this->getConf('navbarUseTitleIcon') === true) {
$logo = $this->getMediaFile('logo', false);
;
if (empty($logo) === false) {
$width = $this->getConf('navbarTitleIconWidth');
$height = $this->getConf('navbarTitleIconHeight');
$styles = '';
if (strlen($width) > 0 || strlen($height) > 0) {
if (ctype_digit($width) === true) {
$styles .= 'max-width:' . intval($width) . 'px;';
} elseif (preg_match('/^\d+(px|rem|em|%)$/', $width) === 1) {
$styles .= 'max-width:' . $width . ';';
} elseif (strcasecmp($width, 'none') === 0) {
$styles .= 'max-width:none;';
}
if (ctype_digit($height) === true) {
$styles .= 'max-height:' . intval($height) . 'px;';
} elseif (preg_match('/^\d+(px|rem|em|%)$/', $height) === 1) {
$styles .= 'max-height:' . $height . ';';
} elseif (strcasecmp($height, 'none') === 0) {
$styles .= 'max-height:none;';
}
if (strlen($styles) > 0) {
$styles = ' style="' . $styles . '"';
}
}//end if
$html .= ' ';
}//end if
}//end if
// Brand title
if ($this->getConf('navbarUseTitleText') === true) {
$html .= '';
$html .= '
' . $conf['title'] . ' ';
if ($this->getConf('navbarUseTaglineText') === true) {
$html .= '
' . $conf['tagline'] . '
';
}
$html .= '
';
}
}//end if
$html .= ' ';
$html .= '
';
// Menus
$html .= '
';
$menus = [$this->getConf('navbarPosLeft', 'none'), $this->getConf('navbarPosMiddle', 'none'),
$this->getConf('navbarPosRight', 'none')
];
foreach ($menus as $menuType) {
switch ($menuType) {
case 'custom':
$html .= $this->stringToNav($this->getConf('navbarCustomMenuText', ''));
break;
case 'search':
$html .= '
';
$html .= $this->includeSearch(false);
$html .= '
';
break;
case 'dokuwiki':
$html .= $this->includeDWMenu(false);
break;
}
}
$html .= '
';
$html .= '
';
$html .= ' ';
// Sub Navbar
if ($showSub === true) {
$sub = $this->includePage('submenu', false);
if (empty($sub) === false) {
$html .= '' . $sub . ' ';
}
}
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Is there a sidebar
*
* @param string $prefix Sidebar prefix to use when searching.
* @return boolean if sidebar exists
*/
public function sidebarExists(string $prefix = '')
{
global $conf;
if (strcasecmp($prefix, 'left') === 0) {
$prefix = '';
}
return $this->pageExists($conf['sidebar' . $prefix]);
}
/**
* Print or return the sidebar content
*
* @param string $prefix Sidebar prefix to use when searching.
* @param boolean $print Print the generated content to the output buffer.
* @param boolean $parse Parse the content.
* @return string generated content
*/
public function includeSidebar(string $prefix = '', bool $print = true, bool $parse = true)
{
global $conf, $ID;
$html = '';
$confPrefix = preg_replace('/[^a-zA-Z0-9]/', '', ucwords($prefix));
$prefix = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($prefix));
if (empty($confPrefix) === true) {
$confPrefix = 'Left';
}
if (strcasecmp($prefix, 'Left') === 0) {
$prefix = '';
}
empty($sidebarPage = $conf[$prefix . 'sidebar']) === true ? $prefix . 'sidebar' : $conf[$prefix . 'sidebar'];
if (
$this->getConf('sidebarShow' . $confPrefix) === true && page_findnearest($sidebarPage) !== false &&
p_get_metadata($ID, 'nosidebar', false) === false
) {
$content = $this->includePage($sidebarPage . 'header', false);
if (empty($content) === false) {
$html .= '';
}
if (empty($prefix) === true) {
$rows = [$this->getConf('sidebarLeftRow1'), $this->getConf('sidebarLeftRow2'),
$this->getConf('sidebarLeftRow3'), $this->getConf('sidebarLeftRow4')
];
foreach ($rows as $row) {
switch ($row) {
case 'search':
$html .= $this->includeSearch(false);
break;
case 'logged in user':
$html .= $this->includeLoggedIn(false);
break;
case 'content':
$content = $this->includePage($sidebarPage, false);
if (empty($content) === false) {
$html .= '';
}
break;
case 'tags':
$html .= '
';
}
}
} else {
$content = $this->includePage($sidebarPage, false);
if (empty($content) === false) {
$html .= '';
}
}//end if
$content = $this->includePage($sidebarPage . 'footer', false);
if (empty($content) === false) {
$html .= '';
}
}//end if
if (empty($html) === true) {
if (empty($prefix) === true && $this->getConf('sidebarAlwaysShowLeft') === true) {
$html = ' ';
}
if ($this->getConf('sidebarAlwaysShow' . ucfirst($prefix)) === true) {
$html = ' ';
}
}
if (empty($html) === false) {
empty($html = '';
}
if ($parse === true) {
$html = $this->includeIcons($html);
}
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Print or return the page tools content
*
* @param boolean $print Print the generated content to the output buffer.
* @param boolean $includeId Include the dw__pagetools id in the element.
* @return string generated content
*/
public function includePageTools(bool $print = true, bool $includeId = false)
{
global $USERINFO;
$loggedIn = (is_array($USERINFO) === true && count($USERINFO) > 0);
$html = '';
$html .= '';
$html .= '';
$html .= ' ';
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Print or return the search bar
*
* @param boolean $print Print content.
* @return string contents of the search bar
*/
public function includeSearch(bool $print = true)
{
global $lang, $ID, $ACT, $QUERY;
$html = '';
$html .= '';
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Print or return content
*
* @param boolean $print Print content.
* @return string contents
*/
public function includeContent(bool $print = true)
{
ob_start();
tpl_content(false);
$html = ob_get_contents();
ob_end_clean();
$html = $this->includeIcons($html);
$html = $this->parseContent($html);
$html .= '
';
if ($this->getConf('heroTitle') === false) {
$html = '
' . $html;
}
$html = '' . $html . '
';
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Print or return footer
*
* @param boolean $print Print footer.
* @return string HTML string containing footer
*/
public function includeFooter(bool $print = true)
{
global $ACT;
$html = '';
$html .= '';
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Print or return breadcrumb trail
*
* @param boolean $print Print out trail.
* @param boolean $parse Parse trail before printing.
* @return string HTML string containing breadcrumbs
*/
public function includeBreadcrumbs(bool $print = true, bool $parse = true)
{
global $conf, $ID, $lang, $ACT;
if (
$this->getConf('breadcrumbHideHome') === true && strcasecmp($ID, 'start') === 0 &&
strcasecmp($ACT, 'show') === 0 || strcasecmp($ACT, 'showtag') === 0 || $conf['breadcrumbs'] === 0
) {
return '';
}
$html = '';
$html .= '
';
if (strcasecmp($ACT, 'show') === 0) {
if ($conf['breadcrumbs'] !== 0) {
if ($this->getConf('breadcrumbPrefix') === false && $this->getConf('breadcrumbSep') === false) {
ob_start();
tpl_breadcrumbs();
$html .= ob_get_contents();
ob_end_clean();
} else {
$sep = '•';
$prefix = $lang['breadcrumb'];
if ($this->getConf('breadcrumbSep') === true) {
$sep = $this->getConf('breadcrumbSepText');
$img = $this->getMediaFile('breadcrumb-sep', false);
if ($img !== false) {
$sep = '
';
}
}
if ($this->getConf('breadcrumbPrefix') === true) {
$prefix = $this->getConf('breadcrumbPrefixText');
$img = $this->getMediaFile('breadcrumb-prefix', false);
if ($img !== false) {
$prefix = '
';
}
}
$crumbs = breadcrumbs();
$html .= '
';
if (empty($prefix) === false) {
$html .= '' . $prefix . ' ';
}
$last = count($crumbs);
$i = 0;
foreach ($crumbs as $id => $name) {
$i++;
if ($i !== 1) {
$html .= '' . $sep . ' ';
}
$html .= '';
$html .= tpl_pagelink($id, null, true);
$html .= ' ';
}
$html .= ' ';
}//end if
}//end if
}//end if
$html .= '
';
$html .= '
';
if ($parse === true) {
$html = $this->includeIcons($html);
}
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Print or return you are here trail
*
* @param boolean $print Print out trail.
* @param boolean $parse Parse trail before printing.
* @return string HTML string containing breadcrumbs
*/
public function includeYouAreHere(bool $print = true, bool $parse = true)
{
global $conf, $ID, $lang, $ACT;
if (
$this->getConf('youarehereHideHome') === true && strcasecmp($ID, 'start') === 0 &&
strcasecmp($ACT, 'show') === 0 || strcasecmp($ACT, 'showtag') === 0 || $conf['youarehere'] === 0
) {
return '';
}
$html = '';
$html .= '
';
if (strcasecmp($ACT, 'show') === 0) {
if ($conf['youarehere'] !== 0) {
if ($this->getConf('youareherePrefix') === false && $this->getConf('youarehereSep') === false) {
$html .= '
';
ob_start();
tpl_youarehere();
$html .= ob_get_contents();
ob_end_clean();
$html .= '
';
} else {
$sep = ' » ';
$prefix = $lang['youarehere'];
if ($this->getConf('youarehereSep') === true) {
$sep = $this->getConf('youarehereSepText');
$img = $this->getMediaFile('youarehere-sep', false);
if ($img !== false) {
$sep = '
';
}
}
if ($this->getConf('youareherePrefix') === true) {
$prefix = $this->getConf('youareherePrefixText');
$img = $this->getMediaFile('youarehere-prefix', false);
if ($img !== false) {
$prefix = '
';
}
}
$html .= '
';
if (empty($prefix) === false) {
$html .= '' . $prefix . ' ';
}
$html .= '' . tpl_pagelink(':' . $conf['start'], null, true) . ' ';
$parts = explode(':', $ID);
$count = count($parts);
$part = '';
for ($i = 0; $i < ($count - 1); $i++) {
$part .= $parts[$i] . ':';
$page = $part;
if ($page === $conf['start']) {
continue;
}
$html .= '' . $sep . ' ';
$html .= '' . tpl_pagelink($page, null, true) . ' ';
}
resolve_pageid('', $page, $exists);
if ((isset($page) === true && $page === $part . $parts[$i]) === false) {
$page = $part . $parts[$i];
if ($page !== $conf['start']) {
$html .= '' . $sep . ' ';
$html .= '' . tpl_pagelink($page, null, true) . ' ';
}
}
$html .= ' ';
}//end if
}//end if
$showLast = $this->getConf('youarehereShowLast');
if ($showLast !== 0) {
preg_match_all('/(
]*>.+?<\/li>)/', $html, $matches);
if (count($matches) > 0 && count($matches[0]) > (($showLast * 2) + 2)) {
$count = count($matches[0]);
$list = '';
// Show Home
$list .= $matches[0][0] . $matches[0][1];
$list .= ' ... ';
for ($i = ($count - ($showLast * 2)); $i <= $count; $i++) {
$list .= $matches[0][$i];
}
$html = preg_replace('/
.*<\/ul>/', '', $html);
}
}
switch ($this->getConf('youarehereHome')) {
case 'none':
$html = preg_replace('/]*>.+?<\/li>/', '', $html, 2);
break;
case 'home':
$html = preg_replace('/(]*>)(.+?)(<\/a>)/', '$1' . tpl_getlang('home') . '$3', $html, 1);
break;
case 'icon':
$html = preg_replace('/( ]*>)(.+?)(<\/a>)/', '$1' .
$this->mikioInlineIcon('home') . '$3', $html, 1);
break;
}
} else {
$html .= '≪ ';
if (isset($_GET['page']) === true) {
$html .= ' Back / ';
}
$html .= 'View Page ';
}//end if
$html .= ' ';
$html .= '
';
if ($parse === true) {
$html = $this->includeIcons($html);
}
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Get Page Title
*
* @return string page title
*/
public function parsePageTitle()
{
global $ID;
$title = p_get_first_heading($ID);
if (strlen($title) <= 0) {
$title = tpl_pagetitle(null, true);
}
$title = $this->includeIcons($title);
return $title;
}
/**
* Print or return hero block
*
* @param boolean $print Print content.
* @return string contents of hero
*/
public function includeHero(bool $print = true)
{
$html = '';
if ($this->getConf('heroTitle') === true) {
$html .= '';
$html .= '
';
$html .= '
';
if (strcasecmp($this->getConf('youareherePosition'), 'hero') === 0) {
$html .= $this->includeYouAreHere(false);
}
if (strcasecmp($this->getConf('breadcrumbPosition'), 'hero') === 0) {
$html .= $this->includeBreadcrumbs(false);
}
$html .= '
';
$html .= $this->parsePageTitle(); // No idea why this requires a blank space afterwards to work?
$html .= ' ';
$html .= ' ';
$html .= '';
$hero_image = $this->getMediaFile('hero', true, $this->getConf('heroImagePropagation', true));
$hero_image_resize_class = '';
if (empty($hero_image) === false) {
$hero_image = ' style="background-image:url(\'' . $hero_image . '\');"';
$hero_image_resize_class = ' mikio-hero-image-resize';
}
$html .= '
';
$html .= '
';
$html .= '
';
}//end if
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Print or return out TOC
*
* @param boolean $print Print TOC.
* @param boolean $parse Parse icons.
* @return string contents of TOC
*/
public function includeTOC(bool $print = true, bool $parse = true)
{
$html = '';
$tocHtml = tpl_toc(true);
if (empty($tocHtml) === false) {
$tocHtml = preg_replace('/<\/a><\/div><\/li>\s*/', '', $tocHtml);
$tocHtml = preg_replace('/\s*<\/ul>\s*/', '', $tocHtml);
$html .= '';
$html .= $tocHtml;
$html .= '
';
}
if ($parse === true) {
$html = $this->includeIcons($html);
}
if ($print === true) {
echo $html;
}
return $html;
}
/**
* Parse the string and replace icon elements with included icon libraries
*
* @param string $str Content to parse.
* @return string parsed string
*/
public function includeIcons(string $str)
{
global $ACT, $MIKIO_ICONS;
$iconTag = $this->getConf('iconTag', 'icon');
if (empty($iconTag) === true) {
return $str;
}
if (
in_array($ACT, ['show', 'showtag', 'revisions', 'index', 'preview']) === true ||
strcasecmp($ACT, 'admin') === 0 && count($MIKIO_ICONS) > 0
) {
$content = $str;
$preview = null;
if (strcasecmp($ACT, 'preview') === 0) {
$html = new \simple_html_dom();
$html->stripRNAttrValues = false;
$html->load($str, true, false);
$preview = $html->find('div.preview');
if (is_array($preview) === true && count($preview) > 0) {
$content = $preview[0]->innertext;
}
}
$page_regex = '/(.*)/';
if (stripos($str, '(.*)[^<]*/';
}
$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(empty($e) < $i || $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)
{
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' => ['footerCustomMenuText', ''],
'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>/',
'tpl»mikio»' .
$search . ' ',
$content
);
}
}
else if(strcasecmp($INPUT->str('page'), 'styling') === 0) {
$content = preg_replace(
'/(\s*\s*\s.*<\/span>\s.*\s.*<\/span>)/',
'$1 ',
$content
);
}
$html = new \simple_html_dom();
$html->stripRNAttrValues = false;
$html->load($content, true, false);
if ($html === false) {
return $content;
}
/* Buttons */
foreach ($html->find('#config__manager button') as $node) {
$c = explode(' ', $node->class);
if (in_array('mikio-button', $c) === false) {
$c[] = 'mikio-button';
}
$node->class = implode(' ', $c);
}
/* Buttons - Primary */
foreach ($html->find('#config__manager [type=submit]') as $node) {
$c = explode(' ', $node->class);
if (in_array('mikio-primary', $c) === false) {
$c[] = 'mikio-primary';
}
$node->class = implode(' ', $c);
}
/* Hide page title if hero is enabled */
if ($this->getConf('heroTitle') === true && $ACT !== 'preview') {
$pageTitle = $this->parsePageTitle();
foreach ($html->find('h1,h2,h3,h4') as $elm) {
if ($elm->innertext === $pageTitle) {
// $elm->innertext = '';
$elm->setAttribute('style', 'display:none');
break;
}
}
}
/* Hero subtitle */
foreach ($html->find('p') as $elm) {
$i = stripos($elm->innertext, '~~hero-subtitle');
if ($i !== false) {
$j = strpos($elm->innertext, '~~', ($i + 2));
if ($j !== false) {
if ($j > ($i + 16)) {
$subtitle = substr($elm->innertext, ($i + 16), ($j - $i - 16));
$this->footerScript['hero-subtitle'] = 'mikio.setHeroSubTitle(\'' . $subtitle . '\')';
// $elm->innertext = substr($elm->innertext, 0, $i + 2) . substr($elm->innertext, $j + 2);
$elm->innertext = preg_replace('/~~hero-subtitle (.+?)~~.*/ui', '', $elm->innertext);
}
break;
}
}
}
/* Hero image */
foreach ($html->find('p') as $elm) {
$image = '';
preg_match('/~~hero-image (.+?)~~(?!.?")/ui', $elm->innertext, $matches);
if (count($matches) > 0) {
preg_match('/ 0) {
$image = $imageTagMatches[1];
} else {
preg_match('/(.+?)[~<]/ui', $matches[1], $imageTagMatches);
if (count($imageTagMatches) > 0) {
$image = $imageTagMatches[1];
} else {
$image = strip_tags($matches[1]);
if (stripos($image, ':') === false) {
$image = str_replace(['{', '}'], '', $image);
$i = stripos($image, '?');
if ($i !== false) {
$image = substr($image, 0, $i);
}
$image = ml($image, '', true, '', false);
}
}
}
$this->footerScript['hero-image'] = 'mikio.setHeroImage(\'' . $image . '\')';
$elm->innertext = preg_replace('/~~hero-image (.+?)~~.*/ui', '', $elm->innertext);
}//end if
}//end foreach
/* Hero colors - ~~hero-colors [background-color] [hero-title-color] [hero-subtitle-color]
[breadcrumb-text-color] [breadcrumb-hover-color] (use 'initial' for original color) */
foreach ($html->find('p') as $elm) {
$i = stripos($elm->innertext, '~~hero-colors');
if ($i !== false) {
$j = strpos($elm->innertext, '~~', ($i + 2));
if ($j !== false) {
if ($j > ($i + 14)) {
$color = substr($elm->innertext, ($i + 14), ($j - $i - 14));
$this->footerScript['hero-colors'] = 'mikio.setHeroColor(\'' . $color . '\')';
$elm->innertext = preg_replace('/~~hero-colors (.+?)~~.*/ui', '', $elm->innertext);
}
break;
}
}
}
/* Hide parts - ~~hide-parts [parts]~~ */
foreach ($html->find('p') as $elm) {
$i = stripos($elm->innertext, '~~hide-parts');
if ($i !== false) {
$j = strpos($elm->innertext, '~~', ($i + 2));
if ($j !== false) {
if ($j > ($i + 13)) {
$parts = explode(' ', substr($elm->innertext, ($i + 13), ($j - $i - 13)));
$script = '';
foreach ($parts as $part) {
// $part = trim($part);
if (strlen($part) > 0) {
$script .= 'mikio.hidePart(\'' . $part . '\');';
}
}
if (strlen($script) > 0) {
$this->footerScript['hide-parts'] = $script;
}
$elm->innertext = preg_replace('/~~hide-parts (.+?)~~.*/ui', '', $elm->innertext);
}
break;
}//end if
}//end if
}//end foreach
/* Page Tags (tag plugin) */
if ($this->getConf('tagsConsolidate') === true) {
$tags = '';
foreach ($html->find('div.tags a') as $elm) {
$tags .= $elm->outertext;
}
foreach ($html->find('div.tags') as $elm) {
$elm->innertext = '';
$elm->setAttribute('style', 'display:none');
}
if (empty($tags) === false) {
$this->footerScript['tags'] = 'mikio.setTags(\'' . $tags . '\')';
}
}
// Configuration Manager
if (strcasecmp($INPUT->str('page'), 'config') === 0) {
// Additional save buttons
foreach ($html->find('#config__manager') as $cm) {
$saveButtons = '';
foreach ($cm->find('p') as $elm) {
$saveButtons = $elm->outertext;
$saveButtons = str_replace('', '
', $saveButtons);
$elm->outertext = '';
}
foreach ($cm->find('fieldset') as $elm) {
$elm->innertext .= $saveButtons;
}
}
}
$content = $html->save();
$html->clear();
unset($html);
return $content;
}
/**
* Get DokuWiki namespace/page/URI as link
*
* @param string $str String to parse.
* @return string parsed URI
*/
public function getLink(string $str)
{
$i = strpos($str, '://');
if ($i !== false) {
return $str;
}
return wl($str);
}
/**
* Check if the user can edit current namespace/page
*
* @return boolean user can edit
*/
public function userCanEdit()
{
global $INFO;
global $ID;
$wiki_file = wikiFN($ID);
if (@file_exists($wiki_file) === false) {
return true;
}
if ($INFO['isadmin'] === true || $INFO['ismanager'] === true) {
return true;
}
// $meta_file = metaFN($ID, '.meta');
if ($INFO['meta']['user'] === false) {
return true;
}
if ($INFO['client'] === $INFO['meta']['user']) {
return true;
}
return false;
}
/**
* Search for and return the uri of a media file
*
* @param string $image Image name to search for (without extension).
* @param boolean $searchCurrentNS Search the current namespace.
* @param boolean $propagate Propagate search through the namespace.
* @return string URI of the found media file
*/
public function getMediaFile(string $image, bool $searchCurrentNS = true, bool $propagate = true)
{
global $INFO;
$ext = ['png', 'jpg', 'gif', 'svg'];
if ($searchCurrentNS === true) {
$prefix[] = ':' . $INFO['namespace'] . ':';
}
if ($propagate === true) {
$prefix[] = ':';
$prefix[] = ':wiki:';
}
$theme = $this->getConf('customTheme');
if (empty($theme) === false) {
$prefix[] = 'themes/' . $theme . '/images/';
}
$prefix[] = 'images/';
$search = [];
foreach ($prefix as $pitem) {
foreach ($ext as $eitem) {
$search[] = $pitem . $image . '.' . $eitem;
}
}
$img = '';
$file = '';
$url = '';
$ismedia = false;
$found = false;
foreach ($search as $img) {
if (strcasecmp(substr($img, 0, 1), ':') === 0) {
$file = mediaFN($img);
$ismedia = true;
} else {
$file = tpl_incdir() . $img;
$ismedia = false;
}
if (file_exists($file) === true) {
$found = true;
break;
}
}
if ($found === false) {
return false;
}
if ($ismedia === true) {
$url = ml($img, '', true, '', false);
} else {
$url = tpl_basedir() . $img;
}
return $url;
}
/**
* Print or return the page title
*
* @param string $page Page id or empty string for current page.
* @return string generated content
*/
public function getPageTitle(string $page = '')
{
global $ID, $conf;
$html = '';
if (empty($page) === true) {
$page = $ID;
}
$html = p_get_first_heading($page);
$html = strip_tags($html);
$html = preg_replace('/\s+/', ' ', $html);
$html .= ' [' . strip_tags($conf['title']) . ']';
$html = trim($html);
return $html;
}
/**
* Return inline theme icon
*
* @param string $type Icon to retreive.
* @return string HTML icon content
*/
public function mikioInlineIcon(string $type)
{
switch ($type) {
case 'wrench':
return ' ';
case 'file':
return ' ';
case 'gear':
return ' ';
case 'user':
return ' ';
case 'search':
return ' ';
case 'home':
return '
';
}//end switch
return '';
}
/**
* Finalize theme
*
* @return void
*/
public function finalize()
{
}
/**
* Show Messages
*
* @return void
*/
public function showMessages()
{
global $ACT;
if ($this->lessIgnored === true) {
msg(
'useLESS is enabled on the Mikio template, however is not supported on this server',
2,
'',
'',
MSG_ADMINS_ONLY
);
}
$show = $this->getConf('showNotifications');
if (
strcasecmp($show, 'always') === 0 ||
(strcasecmp($show, 'admin') === 0 && strcasecmp($ACT, 'admin') === 0)
) {
global $MSG, $MSG_shown;
if (isset($MSG) === false) {
return;
}
if (isset($MSG_shown) === false) {
$MSG_shown = [];
}
foreach ($MSG as $msg) {
$hash = md5($msg['msg']);
if (isset($MSG_shown[$hash]) === true) {
continue;
}
// skip double messages
if (info_msg_allowed($msg) === true) {
echo '
';
echo $msg['msg'];
echo '
';
}
$MSG_shown[$hash] = true;
}
unset($GLOBALS['MSG']);
}//end if
}
/**
* Dokuwiki version
*
* @return string the dw version name
*/
public function dwVersion()
{
if (function_exists('getVersionData') === true) {
$version_data = getVersionData();
if (is_array($version_data) === true && array_key_exists('date', $version_data) === true) {
$version_items = explode(' ', $version_data['date']);
if (count($version_items) >= 2) {
return preg_replace('/[^a-zA-Z0-9 ]+/', '', strtolower($version_items[1]));
}
}
}
return 'unknown';
}
/**
* Dokuwiki version number
*
* @return string the dw version date converted to integer
*/
public function dwVersionNumber()
{
if (function_exists('getVersionData') === true) {
$version_data = getVersionData();
if (is_array($version_data) === true && array_key_exists('date', $version_data) === true) {
$version_items = explode(' ', $version_data['date']);
if (count($version_items) >= 1) {
return intval(preg_replace('/[^0-9]+/', '', strtolower($version_items[0])));
}
}
}
return 0;
}
}
global $TEMPLATE;
$TEMPLATE = \dokuwiki\template\mikio\Template::getInstance();