* @license GPLv2 (http://www.gnu.org/licenses/gpl-2.0.html) */ namespace dokuwiki\template\mikio; if (!defined('DOKU_INC')) die(); require_once('icons/icons.php'); require_once('inc/simple_html_dom.php'); class Template { public $tplDir = ''; public $baseDir = ''; public $footerScript = array(); 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 ($instance === null) { $instance = new Template(); } return $instance; } /** * Register the themes hooks into Dokuwiki */ private function _registerHooks() { global $EVENT_HANDLER; $events_dispatcher = array( '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 */ public function metaHeadersHandler(\Doku_Event $event) { global $MIKIO_ICONS; global $conf; $this->includePage('theme', FALSE, TRUE); $stylesheets = array(); $scripts = array(); if ($this->getConf('customTheme') != '') { if (file_exists($this->tplDir . 'themes/' . $this->getConf('customTheme') . '/style.less')) { $stylesheets[] = $this->baseDir . 'themes/' . $this->getConf('customTheme') . '/style.less'; } else { if (file_exists($this->tplDir . 'themes/' . $this->getConf('customTheme') . '/style.css')) { $stylesheets[] = $this->baseDir . 'themes/' . $this->getConf('customTheme') . '/style.css'; } } if (file_exists($this->tplDir . 'themes/' . $this->getConf('customTheme') . '/script.js')) { $scripts[] = $this->baseDir . 'themes/' . $this->getConf('customTheme') . '/script.js'; } } if (is_array($MIKIO_ICONS) && $this->getConf('iconTag', 'icon') != '') { $icons = array(); foreach ($MIKIO_ICONS as $icon) { if (isset($icon['name']) && isset($icon['css']) && isset($icon['insert'])) { $icons[] = $icon; if ($icon['css'] != '') { 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.js'; if ($this->getConf('useLESS')) { $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 (strtolower(substr($style, -5)) == '.less' && $this->getConf('useLESS')) { $style = $this->baseDir . 'css.php?css=' . str_replace($this->baseDir, '', $style); } array_unshift($event->data['link'], array( 'type' => 'text/css', 'rel' => 'stylesheet', 'href' => $style )); } $set[] = $style; } $set = []; foreach ($scripts as $script) { if (in_array($script, $set) == FALSE) { $script_params = array( 'type' => 'text/javascript', '_data' => '', 'src' => $script ); if ($conf['defer_js']) { $script_params += ['defer' => 'defer']; } $event->data['script'][] = $script_params; } $set[] = $script; } } /** * Print or return the footer meta data * * @param boolean $print print the data to buffer */ public function includeFooterMeta($print = TRUE) { $html = ''; if (count($this->footerScript) > 0) { $html .= ''; } if ($print) 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($key, $default = FALSE) { $value = tpl_getConf($key, $default); switch ($key) { case 'navbarDWMenuType': $value = strtolower($value); if ($value != 'icons' && $value != 'text' && $value != 'both') $value = 'both'; break; case 'navbarDWMenuCombine': $value = strtolower($value); if ($value != 'seperate' && $value != 'dropdown' && $value != 'combine') $value = 'combine'; break; case 'navbarPosLeft': case 'navbarPosMiddle': case 'navbarPosRight': $value = strtolower($value); if ($value != 'none' && $value != 'custom' && $value != 'search' && $value != 'dokuwiki') { if ($key == 'navbarPosLeft') $value = 'none'; if ($key == 'navbarPosMiddle') $value = 'search'; if ($key == 'navbarPosRight') $value = 'dokuwiki'; } break; case 'navbarItemShowCreate': case 'navbarItemShowShow': case 'navbarItemShowRevs': case 'navbarItemShowBacklink': case 'navbarItemShowRecent': case 'navbarItemShowMedia': case 'navbarItemShowIndex': case 'navbarItemShowProfile': case 'navbarItemShowAdmin': $value = strtolower($value); if ($value != 'always' && $value != 'logged in' && $value != 'logged out' && $value != 'never') { $value = 'always'; } break; case 'navbarItemShowLogin': case 'navbarItemShowLogout': $value = strtolower($value); if ($value != 'always' && $value != 'never') { $value = 'always'; } break; case 'searchButton': $value = strtolower($value); if ($value != 'icon' && $value != 'text') $value = 'icon'; break; case 'searchButton': $value = strtolower($value); if ($value != 'icon' && $value != 'text') $value = 'icon'; break; case 'breadcrumbPosition': $value = strtolower($value); if ($value != 'none' && $value != 'top' && $value != 'hero' && $value != 'page') $value = 'top'; break; case 'youareherePosition': $value = strtolower($value); if ($value != 'none' && $value != 'top' && $value != 'hero' && $value != 'page') $value = 'top'; break; case 'youarehereHome': $value = strtolower($value); if ($value != 'none' && $value != 'page title' && $value != 'home' && $value != 'icon') $value = 'page title'; break; case 'sidebarLeftRow1': case 'sidebarLeftRow2': case 'sidebarLeftRow3': case 'sidebarLeftRow4': $value = strtolower($value); if ($value != 'none' && $value != 'logged in user' && $value != 'search' && $value != 'content' && $value != 'tags') { if ($key == 'sidebarLeftRow1') $value = 'logged in user'; if ($key == 'sidebarLeftRow2') $value = 'search'; if ($key == 'sidebarLeftRow3') $value = 'content'; if ($key == 'sidebarLeftRow4') $value = 'none'; } break; case 'pageToolsFloating': case 'pageToolsFooter': $value = strtolower($value); if ($value != 'none' && $value != 'page editors' && $value != 'always') { if ($key == 'pageToolsFloating') $value = 'always'; if ($key == 'pageToolsFooter') $value = 'always'; } break; case 'pageToolsShowCreate': case 'pageToolsShowEdit': case 'pageToolsShowRevs': case 'pageToolsShowBacklink': case 'pageToolsShowTop': $value = strtolower($value); if ($value != 'always' && $value != 'logged in' && $value != 'logged out' && $value != 'never') { $value = 'always'; } break; case 'showNotifications': $value = strtolower($value); if ($value != 'none' && $value != 'admin' && $value != 'always') $value = 'admin'; break; case 'licenseType': $value = strtolower($value); if ($value != 'none' && $value != 'badge' && $value != 'buttom') $value = 'badge'; break; case 'navbarUseTitleIcon': case 'navbarUseTitleText': case 'navbarUseTaglineText': case 'navbarShowSub': case 'heroTitle': case 'heroImagePropagation': case 'breadcrumbPrefix': case 'breadcrumbSep': case 'youareherePrefix': case 'youarehereSep': case 'sidebarShowLeft': case 'sidebarShowRight': case 'tocFull': case 'footerSearch': case 'licenseImageOnly': case 'includePageUseACL': case 'includePagePropagate': case 'youarehereHideHome': case 'tagsConsolidate': case 'footerInPage': case 'sidebarMobileDefaultCollapse': case 'sidebarAlwaysShowLeft': case 'sidebarAlwaysShowRight': $value = (bool)$value; break; case 'youarehereShowLast': $value = (int)$value; break; case 'iconTag': case 'customTheme': case 'navbarCustomMenuText': case 'breadcrumbPrefixText': case 'breadcrumbSepText': case 'youareherePrefixText': case 'youarehereSepText': case 'footerCustomMenuText': break; case 'useLESS': $value = (bool)$value; $lessAvailable = true; // check for less library $lesscLib = '../../../vendor/marcusschwarz/lesserphp/lessc.inc.php'; if (!file_exists($lesscLib)) $lesscLib = $_SERVER['DOCUMENT_ROOT'] . '/vendor/marcusschwarz/lesserphp/lessc.inc.php'; if (!file_exists($lesscLib)) $lesscLib = '../../../../../app/dokuwiki/vendor/marcusschwarz/lesserphp/lessc.inc.php'; if (!file_exists($lesscLib)) $lesscLib = $_SERVER['DOCUMENT_ROOT'] . '/app/dokuwiki/vendor/marcusschwarz/lesserphp/lessc.inc.php'; if (!file_exists($lesscLib)) { $lessAvailable = false; } // check for ctype extensions if (!function_exists('ctype_digit')) { $lessAvailable = false; } if ($value && !$lessAvailable) { $this->lessIgnored = true; $value = false; } break; } 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($page) { ob_start(); tpl_includeFile($page . '.html'); $html = ob_get_contents(); ob_end_clean(); if ($html != '') return TRUE; $useACL = $this->getConf('includePageUseACL'); $propagate = $this->getConf('includePagePropagate'); if ($propagate) { if (page_findnearest($page, $useACL)) return TRUE; } elseif ($useACL && 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($page, $print = TRUE, $parse = TRUE, $classWrapper = '') { ob_start(); tpl_includeFile($page . '.html'); $html = ob_get_contents(); ob_end_clean(); if ($html == '') { $useACL = $this->getConf('includePageUseACL'); $propagate = $this->getConf('includePagePropagate'); $html = ''; $html = tpl_include_page($page, false, $propagate, $useACL); } if ($html != '' && $parse) { $html = $this->parseContent($html); } if ($classWrapper != '' && $html != '') $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 || $e[$i] == '') {
if (isset($icon['$' . $i])) {
$s = str_replace('$' . $i, $icon['$' . $i], $s);
}
} else {
$s = str_replace('$' . $i, $e[$i], $s);
}
}
$dir = '';
if (isset($icon['dir'])) $dir = $this->baseDir . 'icons/' . $icon['dir'] . '/';
$s = str_replace('$0', $dir, $s);
break;
}
}
} else {
$s = str_replace('$1', $matches[1], $icon['insert']);
}
}
}
$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 ($ACT == 'preview') {
if (is_array($preview) && count($preview) > 0) {
$preview[0]->innertext = $content;
}
$str = $html->save();
$html->clear();
unset($html);
} else {
$str = $content;
}
}
return $str;
}
/**
* Parse HTML for theme
*
* @param string $content HTML content to parse
* @return string Parsed content
*/
public function parseContent($content)
{
global $INPUT, $ACT;
// Add Mikio Section titles
if ($INPUT->str('page') == 'config') {
$admin_sections = array(
// Section Insert Before Icon
'navbar' => array('navbarUseTitleIcon', ''),
'search' => array('searchButton', ''),
'hero' => array('heroTitle', ''),
'tags' => array('tagsConsolidate', ''),
'breadcrumb' => array('breadcrumbHideHome', ''),
'youarehere' => array('youareherePosition', ''),
'sidebar' => array('sidebarShowLeft', ''),
'toc' => array('tocFull', ''),
'pagetools' => array('pageToolsFloating', ''),
'footer' => array('footerCustomMenuText', ''),
'license' => array('licenseType', ''),
'acl' => array('includePageUseACL', ''),
'sticky' => array('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) . ' $4', $content);
$content = preg_replace(
'/ \s*\s*(tpl»mikio»' . $search . ')<\/span>/',
'' . $this->mikioInlineIcon($icon) . tpl_getLang('config_' . $section) . ' tpl»mikio»' . $search . '',
$content
);
}
}
if ($ACT == 'admin' && !isset($_GET['page'])) {
$content = preg_replace('/(.*?)<\/ul>.*?(.*?<\/ul>)/s', '$1$2', $content);
}
// Page Revisions - Table Fix
if (strpos($content, 'id="page__revisions"') !== FALSE) {
$content = preg_replace('/(\s.*<\/span>\s.*\s.*<\/span>)/', '$1', $content);
}
$html = new \simple_html_dom;
$html->stripRNAttrValues = false;
$html->load($content, true, false);
if (!$html) return $content;
/* Buttons */
foreach ($html->find('#config__manager button') as $node) {
$c = explode(' ', $node->class);
if (!in_array('mikio-button', $c)) $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)) $c[] = 'mikio-primary';
$node->class = implode(' ', $c);
}
/* Hide page title if hero is enabled */
if ($this->getConf('heroTitle') && $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(array('{', '}'), '', $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);
}
}
/* 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;
}
}
}
/* Page Tags (tag plugin) */
if ($this->getConf('tagsConsolidate')) {
$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 ($tags != '') {
$this->footerScript['tags'] = 'mikio.setTags(\'' . $tags . '\')';
}
}
// Configuration Manager
if ($INPUT->str('page') == 'config') {
// 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($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)) return true;
if ($INFO['isadmin'] || $INFO['ismanager']) return true;
// $meta_file = metaFN($ID, '.meta');
if (!$INFO['meta']['user']) 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 bool $searchCurrentNS search the current namespace
* @return string uri of the found media file
*/
public function getMediaFile($image, $searchCurrentNS = TRUE, $propagate = TRUE)
{
global $INFO;
$ext = array('png', 'jpg', 'gif', 'svg');
if ($searchCurrentNS) $prefix[] = ':' . $INFO['namespace'] . ':';
if ($propagate) {
$prefix[] = ':';
$prefix[] = ':wiki:';
}
$theme = $this->getConf('customTheme');
if ($theme != '') $prefix[] = $this->tplDir . 'themes/' . $theme . '/images/';
$prefix[] = 'images/';
$search = array();
foreach ($prefix as $pitem) {
foreach ($ext as $eitem) {
$search[] = $pitem . $image . '.' . $eitem;
}
}
$img = '';
$file = '';
$url = '';
$ismedia = false;
$found = false;
foreach ($search as $img) {
if (substr($img, 0, 1) == ':') {
$file = mediaFN($img);
$ismedia = true;
} else {
$file = tpl_incdir() . $img;
$ismedia = false;
}
if (file_exists($file)) {
$found = true;
break;
}
}
if (!$found) return false;
if ($ismedia) {
$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($page = '')
{
global $ID, $conf;
$html = '';
if ($page == '') $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($type)
{
switch ($type) {
case 'wrench':
return '';
case 'file':
return '';
case 'gear':
return '';
case 'user':
return '';
case 'search':
return '';
case 'home':
return '';
}
return '';
}
/**
* Finalize theme
*/
public function finalize()
{
}
/**
* Show Messages
*/
public function showMessages()
{
global $ACT;
if ($this->lessIgnored) {
msg('useLESS is enabled on the Mikio template, however is not supported on this server', 2, '', '', MSG_ADMINS_ONLY);
}
$show = $this->getConf('showNotifications');
if ($show == 'always' || ($show == 'admin' && $ACT == 'admin')) {
global $MSG, $MSG_shown;
if (!isset($MSG)) {
return;
}
if (!isset($MSG_shown)) {
$MSG_shown = array();
}
foreach ($MSG as $msg) {
$hash = md5($msg['msg']);
if (isset($MSG_shown[$hash])) {
continue;
}
// skip double messages
if (info_msg_allowed($msg)) {
print '
';
print $msg['msg'];
print '';
}
$MSG_shown[$hash] = true;
}
unset($GLOBALS['MSG']);
}
}
/**
* Dokuwiki version
*
* @return string the dw version name
*/
public function dwVersion() {
if(function_exists('getVersionData')) {
$version_data = getVersionData();
if(is_array($version_data) && array_key_exists('date', $version_data)) {
$version_items = explode(' ', $version_data['date']);
if(count($version_items) >= 2) {
return preg_replace('/[^a-zA-Z0-9 ]+/', '', strtolower($version_items[1]));
}
}
}
return 'unknown';
}
}
global $TEMPLATE;
$TEMPLATE = \dokuwiki\template\mikio\Template::getInstance();