1<?php 2/** 3 * Template Functions 4 * 5 * This file provides template specific custom functions that are 6 * not provided by the DokuWiki core. 7 * It is common practice to start each function with an underscore 8 * to make sure it won't interfere with future core functions. 9 */ 10 11// must be run from within DokuWiki 12if (!defined('DOKU_INC')) die(); 13 14use dokuwiki\Extension\Event; 15 16/** 17 * Modified version of tpl_breadcrumbs() that adds Bulma classes 18 */ 19function _tpl_breadcrumbs() { 20 $out=''; 21 $out .= '<nav class="breadcrumb has-bullet-separator is-small" aria-label="breadcrumbs">'; 22 $out .= '<ul>'; 23 $out .= '<li class="is-active"><a>Trace</a></li>'; 24 $crumbs = breadcrumbs(); //setup crumb trace 25 26 //render crumbs, highlight the last one 27 $last = count($crumbs); 28 $i = 0; 29 foreach($crumbs as $id => $name) { 30 $i++; 31 if($i == $last) { 32 $out .= '<li class="is-active">'; 33 } else { 34 $out .= '<li>'; 35 } 36 $out .= tpl_link(wl($id), hsc($name), 'aria-current="page" title="'.$id.'"', true); 37 $out .= '</li>'; 38 } 39 $out .= '</ul>'; 40 $out .= '</nav>'; 41 echo $out; 42} 43 44/** 45 * Modified version of tpl_content() that adds Bulma classes to basic 46 * elements 47 */ 48function _tpl_content($prependTOC = false) { 49 global $ACT; 50 global $INFO; 51 $INFO['prependTOC'] = $prependTOC; 52 53 ob_start(); 54 Event::createAndTrigger('TPL_ACT_RENDER', $ACT, 'tpl_content_core'); 55 $html_output = ob_get_clean(); 56 $libxml_errors = libxml_use_internal_errors(true); 57 $dom = new DOMDocument(); 58 //$dom->loadHTML($html_output); 59 $dom->loadHTML(mb_convert_encoding($html_output, 'HTML-ENTITIES', 'UTF-8')); 60 libxml_clear_errors(); 61 libxml_use_internal_errors($libxml_errors); 62 // add button class to buttons, reset, and submit 63 foreach ($dom->getElementsByTagName('button') as $ele) { 64 $ele->setAttribute('class', 'button is-small'); 65 } 66 foreach ($dom->getElementsByTagName('reset') as $ele) { 67 $ele->setAttribute('class', 'button is-small'); 68 } 69 foreach ($dom->getElementsByTagName('submit') as $ele) { 70 $ele->setAttribute('class', 'button is-small'); 71 } 72 // add select class to selects 73 foreach ($dom->getElementsByTagName('select') as $ele) { 74 // skip a select on the acl page because it looks weird 75 $name = $ele->getAttribute('name'); 76 if ($name == 'acl_t') continue; 77 $ele->parentNode->setAttribute('class', 'select is-small'); 78 } 79 // add checkbox, radio, and input classes 80 foreach ($dom->getElementsByTagName('input') as $ele) { 81 $type = $ele->getAttribute('type'); 82 switch ($type) { 83 case 'checkbox': 84 $label = $ele->parentNode; 85 $label->setAttribute('class', $label->getAttribute('class') . ' checkbox'); 86 break; 87 case 'radio': 88 $label = $ele->parentNode; 89 $label->setAttribute('class', $label->getAttribute('class') . ' radio'); 90 break; 91 default: 92 $ele->setAttribute('class', $ele->getAttribute('class') . ' input is-small'); 93 break; 94 } 95 //if ($type != 'checkbox') { 96 // $ele->setAttribute('class', $ele->getAttribute('class') . ' input is-small'); 97 //} else { 98 // $label = $ele->parentNode; 99 // $label->setAttribute('class', $label->getAttribute('class') . ' checkbox'); 100 //} 101 } 102 // add proper classes to odered lists 103 foreach ($dom->getElementsByTagName('ol') as $ele) { 104 foreach ($ele->childNodes as $i) { 105 // skip non DOMNode elements 106 if ($i->nodeType != 1) continue; 107 // skip non li elements 108 if ($i->nodeName != 'li') continue; 109 // apply proper class to ordered list based on what level# the 110 // first li element is 111 switch (substr($i->getAttribute('class'), 5, 1)) { 112 case '1': 113 break; 114 case '2': 115 $ele->setAttribute('class', 'is-lower-alpha'); 116 break; 117 case '3': 118 $ele->setAttribute('class', 'is-upper-roman'); 119 break; 120 case '4': 121 $ele->setAttribute('class', 'is-upper-alpha'); 122 break; 123 default: 124 $ele->setAttribute('class', 'is-lower-roman'); 125 break; 126 } 127 // break because we only need to evaluate the very first one 128 // to get the level 129 break; 130 } 131 } 132 // add table class to tables 133 foreach ($dom->getElementsByTagName('table') as $ele) { 134 $ele->setAttribute('class', 'table inline is-bordered is-striped is-narrow is-hoverable'); 135 // get parent div and add table-container class 136 $div = $ele->parentNode; 137 $classes = $div->getAttribute('class'); 138 $div->setAttribute('class', $classes . ' table-container'); 139 } 140 // fix centered table data 141 foreach ($dom->getElementsByTagName('td') as $ele) { 142 $classes = $ele->getAttribute('class'); 143 $classes = str_replace('centeralign', 'has-text-centered', $classes); 144 $classes = str_replace('leftalign', 'has-text-left', $classes); 145 $classes = str_replace('rightalign', 'has-text-right', $classes); 146 $ele->setAttribute('class', $classes); 147 } 148 // fix centered table data and make table headers nicer 149 foreach ($dom->getElementsByTagName('th') as $ele) { 150 $classes = $ele->getAttribute('class'); 151 $classes = $classes . ' has-background-white-ter has-text-weight-bold'; 152 $classes = str_replace('centeralign', 'has-text-centered', $classes); 153 $classes = str_replace('leftalign', 'has-text-left', $classes); 154 $classes = str_replace('rightalign', 'has-text-right', $classes); 155 $ele->setAttribute('class', $classes); 156 } 157 foreach ($dom->getElementsByTagName('thead') as $ele) { 158 $ele->setAttribute('class', 'has-background-white-ter has-text-weight-bold'); 159 } 160 // add textarea class to textareas 161 foreach ($dom->getElementsByTagName('textarea') as $ele) { 162 $ele->setAttribute('class', $ele->getAttribute('class') .' textarea'); 163 } 164 $html_output = $dom->saveHTML($dom->documentElement); 165 Event::createAndTrigger('TPL_CONTENT_DISPLAY', $html_output, 'ptln'); 166 167 return !empty($html_output); 168} 169 170/** 171 * Modified version of tpl_page_tools() that adds Bulma classes and custom formatting 172 */ 173function _tpl_page_tools() { 174 $items = (new \dokuwiki\Menu\PageMenu())->getItems(); 175 $out = ''; 176 $out .= '<ul class="page-tools">'; 177 foreach ($items as $item) { 178 $out .= '<li> '; 179 $out .= '<a '; 180 $out .= buildAttributes($item->getLinkAttributes('button is-light is-small ')); 181 $out .= '>'; 182 //$out .= inlineSVG($item->getSvg()); 183 $out .= $item->getLabel(); 184 $out .= '</a>'; 185 $out .= '</li>'; 186 } 187 $out .= '</ul>'; 188 echo $out; 189} 190 191/** 192 * Custom search form that excludes the button. 193 */ 194function _tpl_searchform($ajax = true, $autocomplete = true) { 195 global $lang; 196 global $ACT; 197 global $QUERY; 198 global $ID; 199 200 // don't print the search form if search action has been disabled 201 if(!actionOK('search')) return false; 202 203 $searchForm = new dokuwiki\Form\Form([ 204 'action' => wl(), 205 'method' => 'get', 206 'role' => 'search', 207 'class' => 'field has-addons is-horizontal pb-2 search', 208 'id' => 'dokuwiki__search', 209 ], true); 210 $searchForm->setHiddenField('do', 'search'); 211 $searchForm->setHiddenField('id', $ID); 212 $searchForm->addTextInput('q') 213 ->addClass('edit input is-small') 214 ->attrs([ 215 'title' => '[F]', 216 'accesskey' => 'f', 217 'placeholder' => $lang['btn_search'], 218 'autocomplete' => $autocomplete ? 'on' : 'off', 219 ]) 220 ->id('qsearch__in') 221 ->val($ACT === 'search' ? $QUERY : '') 222 ->useInput(false) 223 ; 224 if ($ajax) { 225 $searchForm->addTagOpen('div')->id('qsearch__out')->addClass('ajax_qsearch JSpopup'); 226 $searchForm->addTagClose('div'); 227 } 228 Event::createAndTrigger('FORM_QUICKSEARCH_OUTPUT', $searchForm); 229 230 echo $searchForm->toHTML(); 231 232 return true; 233} 234 235/** 236 * Modified version of tpl_sidebar() that adds Bulma classes and custom formatting 237 */ 238function _tpl_sidebar() { 239 $sb = strval(tpl_include_page($conf['sidebar'], false, true)); 240 $dom = new DOMDocument(); 241 //$dom->loadHTML($sb); 242 $dom->loadHTML(mb_convert_encoding($sb, 'HTML-ENTITIES', 'UTF-8')); 243 $uls = $dom->getElementsByTagName('ul'); 244 foreach ($uls as $ul) { 245 $ul->setAttribute('class', 'menu-list'); 246 } 247 echo $dom->saveHTML($dom->documentElement); 248} 249 250/** 251 * Modified version of tpl_toc() that adds Bulma classes and custom formatting 252 */ 253function _tpl_toc() { 254 $t = strval(tpl_toc(true)); 255 $dom = new DOMDocument(); 256 //$dom->loadHTML($t); 257 $dom->loadHTML(mb_convert_encoding($t, 'HTML-ENTITIES', 'UTF-8')); 258 $dw__toc = $dom->getElementById('dw__toc'); 259 $dw__toc->setAttribute('id', 'bulma-toc'); 260 $dw__toc->setAttribute('class', 'is-size-7'); 261 $h3s = $dom->getElementsByTagName('h3'); 262 foreach ($h3s as $h3) { 263 $h3->setAttribute('class', 'has-text-grey-light'); 264 $h3->nodeValue = 'On this page'; 265 } 266 $lis = $dom->getElementsByTagName('li'); 267 foreach ($lis as $li) { 268 if ($li->getAttribute('class') == 'level2') { 269 $li->setAttribute('class', 'level2 pl-2'); 270 } 271 if ($li->getAttribute('class') == 'level3') { 272 $li->setAttribute('class', 'level2 pl-4'); 273 } 274 } 275 $as = $dom->getElementsByTagName('a'); 276 foreach ($as as $a) { 277 $a->setAttribute('class', 'button is-light is-small'); 278 } 279 echo $dom->saveHTML($dom->documentElement); 280} 281 282/** 283 * Modified version of tpl_tools_menu() that adds Bulma classes and custom formatting 284 */ 285function _tpl_tools_menu() { 286 $out = ''; 287 if (!empty($_SERVER['REMOTE_USER'])) { 288 $out .= '<div class="navbar-item has-dropdown is-hoverable">'; 289 $out .= '<a class="navbar-link">Tools</a>'; 290 $out .= '<div class="navbar-dropdown">'; 291 try{ 292 $items = (new \dokuwiki\Menu\SiteMenu())->getItems(); 293 foreach ($items as $item) { 294 $out .= $item->asHtmlLink('navbar-item ', false); 295 } 296 } catch(\RuntimeException $ignored) { 297 // item not available 298 } 299 $out .= '</div>'; 300 $out .= '</div>'; 301 } 302 echo $out; 303} 304 305/** 306 * Modified version of tpl_user_menu() that adds Bulma classes and custom formatting 307 */ 308function _tpl_user_menu() { 309 $out = ''; 310 if (!empty($_SERVER['REMOTE_USER'])) { 311 $out .= '<div class="navbar-item has-dropdown is-hoverable">'; 312 $out .= '<a class="navbar-link">Account</a>'; 313 $out .= '<div class="navbar-dropdown">'; 314 try{ 315 $out .= (new \dokuwiki\Menu\Item\Admin())->asHtmlLink('navbar-item ', false); 316 } catch(\RuntimeException $ignored) { 317 // item not available 318 } 319 try{ 320 $out .= (new \dokuwiki\Menu\Item\Register())->asHtmlLink('navbar-item ', false); 321 } catch(\RuntimeException $ignored) { 322 // item not available 323 } 324 $out .= '<hr class="navbar-divider">'; 325 $out .= (new \dokuwiki\Menu\Item\Login())->asHtmlLink('navbar-item ', false); 326 $out .= '</div>'; 327 $out .= '</div>'; 328 } 329 else { 330 $out .= (new \dokuwiki\Menu\Item\Login())->asHtmlLink('navbar-item ', false); 331 } 332 echo $out; 333} 334