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 within DokuWiki 12if (!defined('DOKU_INC')) die(); 13 14/** 15 * Font-family stack and @font-face stylesheet for the template font setting (conf/metadata.php). 16 * 17 * @return array{sheet:string,stack:string} 18 */ 19function _tpl_font_config() { 20 $key = tpl_getConf('font'); 21 $configs = array( 22 '0xproto' => array( 23 'sheet' => '0xproto.css', 24 'stack' => '"0xProto Nerd Font Mono", "0xProto Nerd Font", monospace', 25 ), 26 '3270' => array( 27 'sheet' => '3270.css', 28 'stack' => '"3270 Nerd Font Mono", "3270 Nerd Font", monospace', 29 ), 30 'agave' => array( 31 'sheet' => 'agave.css', 32 'stack' => '"Agave Nerd Font Mono", "Agave Nerd Font", monospace', 33 ), 34 'anonymouspro' => array( 35 'sheet' => 'anonymouspro.css', 36 'stack' => '"AnonymousPro Nerd Font Mono", "AnonymousPro Nerd Font", monospace', 37 ), 38 'arimo' => array( 39 'sheet' => 'arimo.css', 40 'stack' => '"Arimo Nerd Font Mono", "Arimo Nerd Font", monospace', 41 ), 42 'aurulentsansmono' => array( 43 'sheet' => 'aurulentsansmono.css', 44 'stack' => '"AurulentSansMono Nerd Font Mono", "AurulentSansMono Nerd Font", monospace', 45 ), 46 'bigblueterminal' => array( 47 'sheet' => 'bigblueterminal.css', 48 'stack' => '"BigBlueTermPlus Nerd Font Mono", "BigBlueTermPlus Nerd Font", monospace', 49 ), 50 'bigblueterminal437' => array( 51 'sheet' => 'bigblueterm437-nerd-font.css', 52 'stack' => '"BigBlueTerm437 Nerd Font Mono", "BigBlueTerm437 Nerd Font", monospace', 53 ), 54 'bitstreamverasansmono' => array( 55 'sheet' => 'bitstreamverasansmono.css', 56 'stack' => '"BitstromWera Nerd Font Mono", "BitstromWera Nerd Font", monospace', 57 ), 58 'blexmono' => array( 59 'sheet' => 'blexmono-nerd-font-mono.css', 60 'stack' => '"BlexMono Nerd Font", "BlexMono Nerd Font", monospace', 61 ), 62 'cascadiacode' => array( 63 'sheet' => 'cascadiacode.css', 64 'stack' => '"CaskaydiaCove NF", monospace', 65 ), 66 'cascadiamono' => array( 67 'sheet' => 'cascadiamono.css', 68 'stack' => '"CaskaydiaMono NF", monospace', 69 ), 70 'codenewroman' => array( 71 'sheet' => 'codenewroman.css', 72 'stack' => '"CodeNewRoman Nerd Font Mono", "CodeNewRoman Nerd Font", monospace', 73 ), 74 'comicshannsmono' => array( 75 'sheet' => 'comicshannsmono.css', 76 'stack' => '"ComicShannsMono Nerd Font Mono", "ComicShannsMono Nerd Font", monospace', 77 ), 78 'commitmono' => array( 79 'sheet' => 'commitmono.css', 80 'stack' => '"CommitMono Nerd Font Mono", "CommitMono Nerd Font", monospace', 81 ), 82 'cousine' => array( 83 'sheet' => 'cousine.css', 84 'stack' => '"Cousine Nerd Font Mono", "Cousine Nerd Font", monospace', 85 ), 86 'd2coding' => array( 87 'sheet' => 'd2coding.css', 88 'stack' => '"D2CodingLigature Nerd Font Mono", "D2CodingLigature Nerd Font", monospace', 89 ), 90 'daddytimemono' => array( 91 'sheet' => 'daddytimemono.css', 92 'stack' => '"DaddyTimeMono Nerd Font Mono", "DaddyTimeMono Nerd Font", monospace', 93 ), 94 'dejavusansmono' => array( 95 'sheet' => 'dejavusansmono.css', 96 'stack' => '"DejaVuSansM Nerd Font Mono", "DejaVuSansM Nerd Font", monospace', 97 ), 98 'departuremono' => array( 99 'sheet' => 'departuremono.css', 100 'stack' => '"DepartureMono Nerd Font Mono", "DepartureMono Nerd Font", monospace', 101 ), 102 'droidsansmono' => array( 103 'sheet' => 'droidsansmono.css', 104 'stack' => '"DroidSansM Nerd Font Mono", "DroidSansM Nerd Font", monospace', 105 ), 106 'envycoder' => array( 107 'sheet' => 'envycoder.css', 108 'stack' => '"EnvyCodeR Nerd Font Mono", "EnvyCodeR Nerd Font", monospace', 109 ), 110 'fantasquesansmono' => array( 111 'sheet' => 'fantasquesansmono.css', 112 'stack' => '"FantasqueSansM Nerd Font Mono", "FantasqueSansM Nerd Font", monospace', 113 ), 114 'firacode' => array( 115 'sheet' => 'firacode.css', 116 'stack' => '"FiraCode Nerd Font Mono", "FiraCode Nerd Font", monospace', 117 ), 118 'firamono' => array( 119 'sheet' => 'firamono.css', 120 'stack' => '"FiraMono Nerd Font Mono", "FiraMono Nerd Font", monospace', 121 ), 122 'geistmono' => array( 123 'sheet' => 'geistmono.css', 124 'stack' => '"GeistMono Nerd Font Mono", "GeistMono Nerd Font", monospace', 125 ), 126 'gohu' => array( 127 'sheet' => 'gohu.css', 128 'stack' => '"GohuFont 11 Nerd Font Mono", "GohuFont 11 Nerd Font", monospace', 129 ), 130 'go-mono' => array( 131 'sheet' => 'go-mono.css', 132 'stack' => '"Go-Mono Nerd Font Mono", "Go-Mono Nerd Font", monospace', 133 ), 134 'hack' => array( 135 'sheet' => 'hack.css', 136 'stack' => '"Hack Nerd Font Mono", "Hack Nerd Font", monospace', 137 ), 138 'hasklig' => array( 139 'sheet' => 'hasklig.css', 140 'stack' => '"Hasklug Nerd Font Mono", "Hasklug Nerd Font", monospace', 141 ), 142 'heavydata' => array( 143 'sheet' => 'heavydata.css', 144 'stack' => '"HeavyData Nerd Font", fantasy', 145 ), 146 'hermit' => array( 147 'sheet' => 'hermit.css', 148 'stack' => '"Hurmit Nerd Font Mono", "Hurmit Nerd Font", monospace', 149 ), 150 'ia-writer' => array( 151 'sheet' => 'ia-writer.css', 152 'stack' => '"iMWritingDuo Nerd Font Mono", "iMWritingDuo Nerd Font", monospace', 153 ), 154 'ibmplexmono' => array( 155 'sheet' => 'ibmplexmono.css', 156 'stack' => '"BlexMono Nerd Font Mono", "BlexMono Nerd Font", monospace', 157 ), 158 'inconsolata' => array( 159 'sheet' => 'inconsolata.css', 160 'stack' => '"Inconsolata Nerd Font Mono", "Inconsolata Nerd Font", monospace', 161 ), 162 'inconsolatago' => array( 163 'sheet' => 'inconsolatago.css', 164 'stack' => '"InconsolataGo Nerd Font Mono", "InconsolataGo Nerd Font", monospace', 165 ), 166 'inconsolatalgc' => array( 167 'sheet' => 'inconsolatalgc.css', 168 'stack' => '"Inconsolata LGC Nerd Font Mono", "Inconsolata LGC Nerd Font", monospace', 169 ), 170 'intelonemono' => array( 171 'sheet' => 'intelonemono.css', 172 'stack' => '"IntoneMono NF", monospace', 173 ), 174 'iosevka' => array( 175 'sheet' => 'iosevka.css', 176 'stack' => '"Iosevka NFM", "Iosevka NF", monospace', 177 ), 178 'iosevkaterm' => array( 179 'sheet' => 'iosevkaterm.css', 180 'stack' => '"IosevkaTerm NFM", "IosevkaTerm NF", monospace', 181 ), 182 'iosevkatermslab' => array( 183 'sheet' => 'iosevkatermslab.css', 184 'stack' => '"IosevkaTermSlab NFM", "IosevkaTermSlab NF", monospace', 185 ), 186 'jetbrainsmono' => array( 187 'sheet' => 'jetbrainsmono.css', 188 'stack' => '"JetBrainsMonoNL NFM", "JetBrainsMonoNL NF", monospace', 189 ), 190 'lekton' => array( 191 'sheet' => 'lekton.css', 192 'stack' => '"Lekton Nerd Font Mono", "Lekton Nerd Font", monospace', 193 ), 194 'liberationmono' => array( 195 'sheet' => 'liberationmono.css', 196 'stack' => '"LiberationMono Nerd Font Mono", "LiberationMono Nerd Font", monospace', 197 ), 198 'lilex' => array( 199 'sheet' => 'lilex.css', 200 'stack' => '"Lilex Nerd Font Mono", "Lilex Nerd Font", monospace', 201 ), 202 'mplus' => array( 203 'sheet' => 'mplus.css', 204 'stack' => '"M+1Code Nerd Font Mono", "M+1Code Nerd Font", monospace', 205 ), 206 'martianmono' => array( 207 'sheet' => 'martianmono.css', 208 'stack' => '"MartianMono NFM", "MartianMono NF", monospace', 209 ), 210 'meslo' => array( 211 'sheet' => 'meslo.css', 212 'stack' => '"MesloLGLDZ Nerd Font Mono", "MesloLGLDZ Nerd Font Font", monospace', 213 ), 214 'monaspace' => array( 215 'sheet' => 'monaspace.css', 216 'stack' => '"MonaspiceAr Nerd Font Mono", "MonaspiceAr Nerd Font", monospace', 217 ), 218 'monofur' => array( 219 'sheet' => 'monofur.css', 220 'stack' => '"Monofur Nerd Font Mono", "Monofur Nerd Font", monospace', 221 ), 222 'monoid' => array( 223 'sheet' => 'monoid.css', 224 'stack' => '"Monoid Nerd Font Mono", "Monoid Nerd Font", monospace', 225 ), 226 'mononoki' => array( 227 'sheet' => 'mononoki.css', 228 'stack' => '"Mononoki Nerd Font Mono", "Mononoki Nerd Font", monospace', 229 ), 230 'nerdfontssymbolsonly' => array( 231 'sheet' => 'nerdfontssymbolsonly.css', 232 'stack' => '"Symbols Nerd Font Mono", "Symbols Nerd Font", monospace', 233 ), 234 'noto' => array( 235 'sheet' => 'noto.css', 236 'stack' => '"NotoMono NFM", "NotoMono NF", monospace', 237 ), 238 'opendyslexic' => array( 239 'sheet' => 'opendyslexic.css', 240 'stack' => '"OpenDyslexicM Nerd Font Mono", "OpenDyslexicM Nerd Font", monospace', 241 ), 242 'overpass' => array( 243 'sheet' => 'overpass.css', 244 'stack' => '"OverpassM Nerd Font Mono", "OverpassM Nerd Font", monospace', 245 ), 246 'profont' => array( 247 'sheet' => 'profont.css', 248 'stack' => '"ProFont IIx Nerd Font Mono", "ProFont IIx Nerd Font", monospace', 249 ), 250 'proggyclean' => array( 251 'sheet' => 'proggyclean.css', 252 'stack' => '"ProggyClean Nerd Font Mono", "ProggyClean Nerd Font", monospace', 253 ), 254 'recursive' => array( 255 'sheet' => 'recursive.css', 256 'stack' => '"RecMonoCasual Nerd Font Mono", "RecMonoCasual Nerd Font", monospace', 257 ), 258 'robotomono' => array( 259 'sheet' => 'robotomono.css', 260 'stack' => '"RobotoMono Nerd Font Mono", "RobotoMono Nerd Font", monospace', 261 ), 262 'sharetechmono' => array( 263 'sheet' => 'sharetechmono.css', 264 'stack' => '"ShureTechMono Nerd Font Mono", "ShureTechMono Nerd Font", monospace', 265 ), 266 'sourcecodepro' => array( 267 'sheet' => 'sourcecodepro.css', 268 'stack' => '"SauceCodePro NFM", "SauceCodePro NF", monospace', 269 ), 270 'spacemono' => array( 271 'sheet' => 'spacemono.css', 272 'stack' => '"SpaceMono Nerd Font Mono", "SpaceMono Nerd Font", monospace', 273 ), 274 'terminus' => array( 275 'sheet' => 'terminus.css', 276 'stack' => '"Terminess Nerd Font Mono", "Terminess Nerd Font", monospace', 277 ), 278 'tinos' => array( 279 'sheet' => 'tinos.css', 280 'stack' => '"Tinos Nerd Font", serif', 281 ), 282 'ubuntu' => array( 283 'sheet' => 'ubuntu.css', 284 'stack' => '"Ubuntu Nerd Font", sans-serif', 285 ), 286 'ubuntumono' => array( 287 'sheet' => 'ubuntumono.css', 288 'stack' => '"UbuntuMono Nerd Font Mono", "UbuntuMono Nerd Font", monospace', 289 ), 290 'ubuntusans' => array( 291 'sheet' => 'ubuntusans.css', 292 'stack' => '"UbuntuSansMono NFM", "UbuntuSansMono NF", monospace', 293 ), 294 'victormono' => array( 295 'sheet' => 'victormono.css', 296 'stack' => '"VictorMono NFM", "VictorMono NF", monospace', 297 ), 298 'zedmono' => array( 299 'sheet' => 'zedmono.css', 300 'stack' => '"ZedMono NFM", "ZedMono NF", monospace', 301 ), 302 ); 303 return isset($configs[$key]) ? $configs[$key] : $configs['firacode']; 304} 305 306/** 307 * Filesystem path to this template directory (trailing slash). 308 * 309 * @return string 310 */ 311function _tpl_fsdir() { 312 return dirname(__FILE__) . '/'; 313} 314 315/** 316 * Return a DokuWiki HTTP client when available (compatible with old and new cores). 317 * 318 * @return \dokuwiki\HTTP\DokuHTTPClient|DokuHTTPClient|null 319 */ 320function _tpl_http_client() { 321 if (class_exists('\\dokuwiki\\HTTP\\DokuHTTPClient')) { 322 return new \dokuwiki\HTTP\DokuHTTPClient(); 323 } 324 if (class_exists('DokuHTTPClient')) { 325 return new DokuHTTPClient(); 326 } 327 $legacy = DOKU_INC . 'inc/HTTPClient.php'; 328 if (is_readable($legacy)) { 329 require_once $legacy; 330 return new DokuHTTPClient(); 331 } 332 return null; 333} 334 335/** 336 * Download missing .woff2 files for the selected font (local CDN mode only). 337 * 338 * Only fetches the files referenced by the active @font-face sheet (~few MB), 339 * not the full Nerd Fonts bundle. 340 */ 341function _tpl_ensure_local_fonts($sheet) { 342 $css_path = _tpl_fsdir() . 'assets/nerd-fonts/' . $sheet; 343 if (!is_readable($css_path)) return; 344 345 $css = file_get_contents($css_path); 346 if ($css === false || !preg_match_all('/url\("fonts\/([^"]+\.woff2)"\)/', $css, $matches)) return; 347 348 $fonts_dir = _tpl_fsdir() . 'assets/nerd-fonts/fonts/'; 349 if (!function_exists('io_mkdir_p') || !function_exists('io_saveFile')) return; 350 io_mkdir_p($fonts_dir); 351 352 $http = _tpl_http_client(); 353 if (!$http) return; 354 $http->timeout = 60; 355 $http->max_bodysize = 0; 356 357 $base_url = 'https://cdn.jsdelivr.net/gh/mshaugh/nerdfont-webfonts/build/fonts/'; 358 foreach (array_unique($matches[1]) as $file) { 359 $dest = $fonts_dir . $file; 360 if (is_file($dest) && filesize($dest) > 0) continue; 361 362 $data = $http->get($base_url . rawurlencode($file)); 363 if ($data !== false && strlen($data) > 128) { 364 io_saveFile($dest, $data); 365 } 366 } 367} 368 369/** 370 * Loads the glyph @font-face sheet and outputs font-family rules (after tpl_metaheaders()). 371 */ 372function _tpl_font_headers() { 373 $cfg = _tpl_font_config(); 374 $cdn = tpl_getConf('cdn'); 375 376 switch ($cdn) { 377 case 'github': 378 $stylesheet_url = 'https://mshaugh.github.io/nerdfont-webfonts/build/' . $cfg['sheet']; 379 break; 380 case 'jsdelivr': 381 $stylesheet_url = 'https://cdn.jsdelivr.net/gh/mshaugh/nerdfont-webfonts/build/' . $cfg['sheet']; 382 break; 383 case 'local': 384 _tpl_ensure_local_fonts($cfg['sheet']); 385 $stylesheet_url = tpl_basedir() . 'assets/nerd-fonts/' . $cfg['sheet']; 386 break; 387 default: 388 $stylesheet_url = tpl_basedir() . 'assets/nerd-fonts/' . $cfg['sheet']; 389 break; 390 } 391 392 echo '<link rel="stylesheet" href="' . hsc($stylesheet_url) . '" />' . PHP_EOL; 393 echo '<style type="text/css">' . PHP_EOL 394 . 'body,' . PHP_EOL 395 . 'input,' . PHP_EOL 396 . 'textarea,' . PHP_EOL 397 . 'select,' . PHP_EOL 398 . 'button,' . PHP_EOL 399 . '.hacker-button,' . PHP_EOL 400 . 'pre,' . PHP_EOL 401 . 'code,' . PHP_EOL 402 . 'kbd, samp,' . PHP_EOL 403 . '#mediamanager__page h2,' . PHP_EOL 404 . '#mediamanager__page h3' . PHP_EOL 405 . '{ font-family: ' . $cfg['stack'] . '; }' . PHP_EOL 406 . "</style>"; 407} 408 409function _tpl_usertools() { 410 /* The optional second parameter of tpl_action() switches between a link and a button, 411 e.g. a button inside a <li> would be: tpl_action('edit', 0, 'li') */ 412 tpl_toolsevent('usertools', array( 413 'admin' => tpl_action('admin', 1, 'li', 1), 414 'profile' => tpl_action('profile', 1, 'li', 1), 415 'register' => tpl_action('register', 1, 'li', 1), 416 'login' => tpl_action('login', 1, 'li', 1), 417 )); 418} 419 420function _tpl_sitetools() { 421 tpl_toolsevent('sitetools', array( 422 'recent' => tpl_action('recent', 1, 'li', 1), 423 'media' => tpl_action('media', 1, 'li', 1), 424 'index' => tpl_action('index', 1, 'li', 1), 425 )); 426} 427 428function _tpl_pagetools() { 429 tpl_toolsevent('pagetools', array( 430 'edit' => tpl_action('edit', 1, 'li', 1), 431 'revisions' => tpl_action('revisions', 1, 'li', 1), 432 'backlink' => tpl_action('backlink', 1, 'li', 1), 433 'subscribe' => tpl_action('subscribe', 1, 'li', 1), 434 'revert' => tpl_action('revert', 1, 'li', 1), 435 'top' => tpl_action('top', 1, 'li', 1), 436 )); 437} 438 439function _tpl_detailtools() { 440 echo tpl_action('mediaManager', 1, 'li', 1); 441 echo tpl_action('img_backto', 1, 'li', 1); 442} 443