1<?php 2/** 3 * DokuWiki template functions 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9if(!defined('DOKU_INC')) die('meh.'); 10 11/** 12 * Returns the path to the given template, uses 13 * default one if the custom version doesn't exist. 14 * 15 * @author Andreas Gohr <andi@splitbrain.org> 16 */ 17function template($tpl){ 18 global $conf; 19 20 if(@is_readable(DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$tpl)) 21 return DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$tpl; 22 23 return DOKU_INC.'lib/tpl/default/'.$tpl; 24} 25 26 27/** 28 * Convenience function to access template dir from local FS 29 * 30 * This replaces the deprecated DOKU_TPLINC constant 31 * 32 * @author Andreas Gohr <andi@splitbrain.org> 33 */ 34function tpl_incdir(){ 35 global $conf; 36 return DOKU_INC.'lib/tpl/'.$conf['template'].'/'; 37} 38 39/** 40 * Convenience function to access template dir from web 41 * 42 * This replaces the deprecated DOKU_TPL constant 43 * 44 * @author Andreas Gohr <andi@splitbrain.org> 45 */ 46function tpl_basedir(){ 47 global $conf; 48 return DOKU_BASE.'lib/tpl/'.$conf['template'].'/'; 49} 50 51/** 52 * Print the content 53 * 54 * This function is used for printing all the usual content 55 * (defined by the global $ACT var) by calling the appropriate 56 * outputfunction(s) from html.php 57 * 58 * Everything that doesn't use the main template file isn't 59 * handled by this function. ACL stuff is not done here either. 60 * 61 * @author Andreas Gohr <andi@splitbrain.org> 62 */ 63function tpl_content($prependTOC=true) { 64 global $ACT; 65 global $INFO; 66 $INFO['prependTOC'] = $prependTOC; 67 68 ob_start(); 69 trigger_event('TPL_ACT_RENDER',$ACT,'tpl_content_core'); 70 $html_output = ob_get_clean(); 71 trigger_event('TPL_CONTENT_DISPLAY',$html_output,'ptln'); 72 73 return !empty($html_output); 74} 75 76function tpl_content_core(){ 77 global $ACT; 78 global $TEXT; 79 global $PRE; 80 global $SUF; 81 global $SUM; 82 global $IDX; 83 84 switch($ACT){ 85 case 'show': 86 html_show(); 87 break; 88 case 'locked': 89 html_locked(); 90 case 'edit': 91 case 'recover': 92 html_edit(); 93 break; 94 case 'preview': 95 html_edit(); 96 html_show($TEXT); 97 break; 98 case 'draft': 99 html_draft(); 100 break; 101 case 'search': 102 html_search(); 103 break; 104 case 'revisions': 105 $first = isset($_REQUEST['first']) ? intval($_REQUEST['first']) : 0; 106 html_revisions($first); 107 break; 108 case 'diff': 109 html_diff(); 110 break; 111 case 'recent': 112 if (is_array($_REQUEST['first'])) { 113 $_REQUEST['first'] = array_keys($_REQUEST['first']); 114 $_REQUEST['first'] = $_REQUEST['first'][0]; 115 } 116 $first = is_numeric($_REQUEST['first']) ? intval($_REQUEST['first']) : 0; 117 $show_changes = $_REQUEST['show_changes']; 118 html_recent($first, $show_changes); 119 break; 120 case 'index': 121 html_index($IDX); #FIXME can this be pulled from globals? is it sanitized correctly? 122 break; 123 case 'backlink': 124 html_backlinks(); 125 break; 126 case 'conflict': 127 html_conflict(con($PRE,$TEXT,$SUF),$SUM); 128 html_diff(con($PRE,$TEXT,$SUF),false); 129 break; 130 case 'login': 131 html_login(); 132 break; 133 case 'register': 134 html_register(); 135 break; 136 case 'resendpwd': 137 html_resendpwd(); 138 break; 139 case 'denied': 140 print p_locale_xhtml('denied'); 141 break; 142 case 'profile' : 143 html_updateprofile(); 144 break; 145 case 'admin': 146 tpl_admin(); 147 break; 148 case 'subscribe': 149 tpl_subscribe(); 150 break; 151 case 'media': 152 tpl_media(); 153 break; 154 default: 155 $evt = new Doku_Event('TPL_ACT_UNKNOWN',$ACT); 156 if ($evt->advise_before()) 157 msg("Failed to handle command: ".hsc($ACT),-1); 158 $evt->advise_after(); 159 unset($evt); 160 return false; 161 } 162 return true; 163} 164 165/** 166 * Places the TOC where the function is called 167 * 168 * If you use this you most probably want to call tpl_content with 169 * a false argument 170 * 171 * @author Andreas Gohr <andi@splitbrain.org> 172 */ 173function tpl_toc($return=false){ 174 global $TOC; 175 global $ACT; 176 global $ID; 177 global $REV; 178 global $INFO; 179 global $conf; 180 $toc = array(); 181 182 if(is_array($TOC)){ 183 // if a TOC was prepared in global scope, always use it 184 $toc = $TOC; 185 }elseif(($ACT == 'show' || substr($ACT,0,6) == 'export') && !$REV && $INFO['exists']){ 186 // get TOC from metadata, render if neccessary 187 $meta = p_get_metadata($ID, false, METADATA_RENDER_USING_CACHE); 188 if(isset($meta['internal']['toc'])){ 189 $tocok = $meta['internal']['toc']; 190 }else{ 191 $tocok = true; 192 } 193 $toc = $meta['description']['tableofcontents']; 194 if(!$tocok || !is_array($toc) || !$conf['tocminheads'] || count($toc) < $conf['tocminheads']){ 195 $toc = array(); 196 } 197 }elseif($ACT == 'admin'){ 198 // try to load admin plugin TOC FIXME: duplicates code from tpl_admin 199 $plugin = null; 200 if (!empty($_REQUEST['page'])) { 201 $pluginlist = plugin_list('admin'); 202 if (in_array($_REQUEST['page'], $pluginlist)) { 203 // attempt to load the plugin 204 $plugin =& plugin_load('admin',$_REQUEST['page']); 205 } 206 } 207 if ( ($plugin !== null) && 208 (!$plugin->forAdminOnly() || $INFO['isadmin']) ){ 209 $toc = $plugin->getTOC(); 210 $TOC = $toc; // avoid later rebuild 211 } 212 } 213 214 trigger_event('TPL_TOC_RENDER', $toc, null, false); 215 $html = html_TOC($toc); 216 if($return) return $html; 217 echo $html; 218} 219 220/** 221 * Handle the admin page contents 222 * 223 * @author Andreas Gohr <andi@splitbrain.org> 224 */ 225function tpl_admin(){ 226 global $INFO; 227 global $TOC; 228 229 $plugin = null; 230 if (!empty($_REQUEST['page'])) { 231 $pluginlist = plugin_list('admin'); 232 233 if (in_array($_REQUEST['page'], $pluginlist)) { 234 235 // attempt to load the plugin 236 $plugin =& plugin_load('admin',$_REQUEST['page']); 237 } 238 } 239 240 if ($plugin !== null){ 241 if(!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet 242 if($INFO['prependTOC']) tpl_toc(); 243 $plugin->html(); 244 }else{ 245 html_admin(); 246 } 247 return true; 248} 249 250/** 251 * Print the correct HTML meta headers 252 * 253 * This has to go into the head section of your template. 254 * 255 * @triggers TPL_METAHEADER_OUTPUT 256 * @param boolean $alt Should feeds and alternative format links be added? 257 * @author Andreas Gohr <andi@splitbrain.org> 258 */ 259function tpl_metaheaders($alt=true){ 260 global $ID; 261 global $REV; 262 global $INFO; 263 global $JSINFO; 264 global $ACT; 265 global $QUERY; 266 global $lang; 267 global $conf; 268 $it=2; 269 270 // prepare the head array 271 $head = array(); 272 273 // prepare seed for js and css 274 $tseed = 0; 275 $depends = getConfigFiles('main'); 276 foreach($depends as $f) { 277 $time = @filemtime($f); 278 if($time > $tseed) $tseed = $time; 279 } 280 281 // the usual stuff 282 $head['meta'][] = array( 'name'=>'generator', 'content'=>'DokuWiki'); 283 $head['link'][] = array( 'rel'=>'search', 'type'=>'application/opensearchdescription+xml', 284 'href'=>DOKU_BASE.'lib/exe/opensearch.php', 'title'=>$conf['title'] ); 285 $head['link'][] = array( 'rel'=>'start', 'href'=>DOKU_BASE ); 286 if(actionOK('index')){ 287 $head['link'][] = array( 'rel'=>'contents', 'href'=> wl($ID,'do=index',false,'&'), 288 'title'=>$lang['btn_index'] ); 289 } 290 291 if($alt){ 292 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml', 293 'title'=>'Recent Changes', 'href'=>DOKU_BASE.'feed.php'); 294 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml', 295 'title'=>'Current Namespace', 296 'href'=>DOKU_BASE.'feed.php?mode=list&ns='.$INFO['namespace']); 297 if(($ACT == 'show' || $ACT == 'search') && $INFO['writable']){ 298 $head['link'][] = array( 'rel'=>'edit', 299 'title'=>$lang['btn_edit'], 300 'href'=> wl($ID,'do=edit',false,'&')); 301 } 302 303 if($ACT == 'search'){ 304 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml', 305 'title'=>'Search Result', 306 'href'=>DOKU_BASE.'feed.php?mode=search&q='.$QUERY); 307 } 308 309 if(actionOK('export_xhtml')){ 310 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/html', 'title'=>'Plain HTML', 311 'href'=>exportlink($ID, 'xhtml', '', false, '&')); 312 } 313 314 if(actionOK('export_raw')){ 315 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/plain', 'title'=>'Wiki Markup', 316 'href'=>exportlink($ID, 'raw', '', false, '&')); 317 } 318 } 319 320 // setup robot tags apropriate for different modes 321 if( ($ACT=='show' || $ACT=='export_xhtml') && !$REV){ 322 if($INFO['exists']){ 323 //delay indexing: 324 if((time() - $INFO['lastmod']) >= $conf['indexdelay']){ 325 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow'); 326 }else{ 327 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow'); 328 } 329 $head['link'][] = array( 'rel'=>'canonical', 'href'=>wl($ID,'',true,'&') ); 330 }else{ 331 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,follow'); 332 } 333 }elseif(defined('DOKU_MEDIADETAIL')){ 334 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow'); 335 }else{ 336 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow'); 337 } 338 339 // set metadata 340 if($ACT == 'show' || $ACT=='export_xhtml'){ 341 // date of modification 342 if($REV){ 343 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$REV)); 344 }else{ 345 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$INFO['lastmod'])); 346 } 347 348 // keywords (explicit or implicit) 349 if(!empty($INFO['meta']['subject'])){ 350 $head['meta'][] = array( 'name'=>'keywords', 'content'=>join(',',$INFO['meta']['subject'])); 351 }else{ 352 $head['meta'][] = array( 'name'=>'keywords', 'content'=>str_replace(':',',',$ID)); 353 } 354 } 355 356 // load stylesheets 357 $head['link'][] = array('rel'=>'stylesheet', 'type'=>'text/css', 358 'href'=>DOKU_BASE.'lib/exe/css.php?t='.$conf['template'].'&tseed='.$tseed); 359 360 // make $INFO and other vars available to JavaScripts 361 $json = new JSON(); 362 $script = "var NS='".$INFO['namespace']."';"; 363 if($conf['useacl'] && $_SERVER['REMOTE_USER']){ 364 $script .= "var SIG='".toolbar_signature()."';"; 365 } 366 $script .= 'var JSINFO = '.$json->encode($JSINFO).';'; 367 $head['script'][] = array( 'type'=>'text/javascript', '_data'=> $script); 368 369 // load external javascript 370 $head['script'][] = array( 'type'=>'text/javascript', 'charset'=>'utf-8', '_data'=>'', 371 'src'=>DOKU_BASE.'lib/exe/js.php'.'?tseed='.$tseed); 372 373 // trigger event here 374 trigger_event('TPL_METAHEADER_OUTPUT',$head,'_tpl_metaheaders_action',true); 375 return true; 376} 377 378/** 379 * prints the array build by tpl_metaheaders 380 * 381 * $data is an array of different header tags. Each tag can have multiple 382 * instances. Attributes are given as key value pairs. Values will be HTML 383 * encoded automatically so they should be provided as is in the $data array. 384 * 385 * For tags having a body attribute specify the the body data in the special 386 * attribute '_data'. This field will NOT BE ESCAPED automatically. 387 * 388 * @author Andreas Gohr <andi@splitbrain.org> 389 */ 390function _tpl_metaheaders_action($data){ 391 foreach($data as $tag => $inst){ 392 foreach($inst as $attr){ 393 echo '<',$tag,' ',buildAttributes($attr); 394 if(isset($attr['_data']) || $tag == 'script'){ 395 if($tag == 'script' && $attr['_data']) 396 $attr['_data'] = "<!--//--><![CDATA[//><!--\n". 397 $attr['_data']. 398 "\n//--><!]]>"; 399 400 echo '>',$attr['_data'],'</',$tag,'>'; 401 }else{ 402 echo '/>'; 403 } 404 echo "\n"; 405 } 406 } 407} 408 409/** 410 * Print a link 411 * 412 * Just builds a link. 413 * 414 * @author Andreas Gohr <andi@splitbrain.org> 415 */ 416function tpl_link($url,$name,$more='',$return=false){ 417 $out = '<a href="'.$url.'" '; 418 if ($more) $out .= ' '.$more; 419 $out .= ">$name</a>"; 420 if ($return) return $out; 421 print $out; 422 return true; 423} 424 425/** 426 * Prints a link to a WikiPage 427 * 428 * Wrapper around html_wikilink 429 * 430 * @author Andreas Gohr <andi@splitbrain.org> 431 */ 432function tpl_pagelink($id,$name=null){ 433 print html_wikilink($id,$name); 434 return true; 435} 436 437/** 438 * get the parent page 439 * 440 * Tries to find out which page is parent. 441 * returns false if none is available 442 * 443 * @author Andreas Gohr <andi@splitbrain.org> 444 */ 445function tpl_getparent($id){ 446 global $conf; 447 $parent = getNS($id).':'; 448 resolve_pageid('',$parent,$exists); 449 if($parent == $id) { 450 $pos = strrpos (getNS($id),':'); 451 $parent = substr($parent,0,$pos).':'; 452 resolve_pageid('',$parent,$exists); 453 if($parent == $id) return false; 454 } 455 return $parent; 456} 457 458/** 459 * Print one of the buttons 460 * 461 * @author Adrian Lang <mail@adrianlang.de> 462 * @see tpl_get_action 463 */ 464function tpl_button($type,$return=false){ 465 $data = tpl_get_action($type); 466 if ($data === false) { 467 return false; 468 } elseif (!is_array($data)) { 469 $out = sprintf($data, 'button'); 470 } else { 471 extract($data); 472 if ($id === '#dokuwiki__top') { 473 $out = html_topbtn(); 474 } else { 475 $out = html_btn($type, $id, $accesskey, $params, $method); 476 } 477 } 478 if ($return) return $out; 479 echo $out; 480 return true; 481} 482 483/** 484 * Like the action buttons but links 485 * 486 * @author Adrian Lang <mail@adrianlang.de> 487 * @see tpl_get_action 488 */ 489function tpl_actionlink($type,$pre='',$suf='',$inner='',$return=false){ 490 global $lang; 491 $data = tpl_get_action($type); 492 if ($data === false) { 493 return false; 494 } elseif (!is_array($data)) { 495 $out = sprintf($data, 'link'); 496 } else { 497 extract($data); 498 if (strpos($id, '#') === 0) { 499 $linktarget = $id; 500 } else { 501 $linktarget = wl($id, $params); 502 } 503 $caption = $lang['btn_' . $type]; 504 $akey = $addTitle = ''; 505 if($accesskey){ 506 $akey = 'accesskey="'.$accesskey.'" '; 507 $addTitle = ' ['.strtoupper($accesskey).']'; 508 } 509 $out = tpl_link($linktarget, $pre.(($inner)?$inner:$caption).$suf, 510 'class="action ' . $type . '" ' . 511 $akey . 'rel="nofollow" ' . 512 'title="' . hsc($caption).$addTitle . '"', 1); 513 } 514 if ($return) return $out; 515 echo $out; 516 return true; 517} 518 519/** 520 * Check the actions and get data for buttons and links 521 * 522 * Available actions are 523 * 524 * edit - edit/create/show/draft 525 * history - old revisions 526 * recent - recent changes 527 * login - login/logout - if ACL enabled 528 * profile - user profile (if logged in) 529 * index - The index 530 * admin - admin page - if enough rights 531 * top - back to top 532 * back - back to parent - if available 533 * backlink - links to the list of backlinks 534 * subscribe/subscription- subscribe/unsubscribe 535 * 536 * @author Andreas Gohr <andi@splitbrain.org> 537 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 538 * @author Adrian Lang <mail@adrianlang.de> 539 */ 540function tpl_get_action($type) { 541 global $ID; 542 global $INFO; 543 global $REV; 544 global $ACT; 545 global $conf; 546 global $auth; 547 548 // check disabled actions and fix the badly named ones 549 if($type == 'history') $type='revisions'; 550 if(!actionOK($type)) return false; 551 552 $accesskey = null; 553 $id = $ID; 554 $method = 'get'; 555 $params = array('do' => $type); 556 switch($type){ 557 case 'edit': 558 // most complicated type - we need to decide on current action 559 if($ACT == 'show' || $ACT == 'search'){ 560 $method = 'post'; 561 if($INFO['writable']){ 562 $accesskey = 'e'; 563 if(!empty($INFO['draft'])) { 564 $type = 'draft'; 565 $params['do'] = 'draft'; 566 } else { 567 $params['rev'] = $REV; 568 if(!$INFO['exists']){ 569 $type = 'create'; 570 } 571 } 572 }else{ 573 if(!actionOK('source')) return false; //pseudo action 574 $params['rev'] = $REV; 575 $type = 'source'; 576 $accesskey = 'v'; 577 } 578 }else{ 579 $params = array(); 580 $type = 'show'; 581 $accesskey = 'v'; 582 } 583 break; 584 case 'revisions': 585 $type = 'revs'; 586 $accesskey = 'o'; 587 break; 588 case 'recent': 589 $accesskey = 'r'; 590 break; 591 case 'index': 592 $accesskey = 'x'; 593 break; 594 case 'top': 595 $accesskey = 't'; 596 $params = array(); 597 $id = '#dokuwiki__top'; 598 break; 599 case 'back': 600 $parent = tpl_getparent($ID); 601 if (!$parent) { 602 return false; 603 } 604 $id = $parent; 605 $params = array(); 606 $accesskey = 'b'; 607 break; 608 case 'login': 609 $params['sectok'] = getSecurityToken(); 610 if(isset($_SERVER['REMOTE_USER'])){ 611 if (!actionOK('logout')) { 612 return false; 613 } 614 $params['do'] = 'logout'; 615 $type = 'logout'; 616 } 617 break; 618 case 'register': 619 if($_SERVER['REMOTE_USER']){ 620 return false; 621 } 622 break; 623 case 'resendpwd': 624 if($_SERVER['REMOTE_USER']){ 625 return false; 626 } 627 break; 628 case 'admin': 629 if(!$INFO['ismanager']){ 630 return false; 631 } 632 break; 633 case 'revert': 634 if(!$INFO['ismanager'] || !$REV || !$INFO['writable']) { 635 return false; 636 } 637 $params['rev'] = $REV; 638 $params['sectok'] = getSecurityToken(); 639 break; 640 case 'subscription': 641 $type = 'subscribe'; 642 $params['do'] = 'subscribe'; 643 case 'subscribe': 644 if(!$_SERVER['REMOTE_USER']){ 645 return false; 646 } 647 break; 648 case 'backlink': 649 break; 650 case 'profile': 651 if(!isset($_SERVER['REMOTE_USER'])){ 652 return false; 653 } 654 break; 655 case 'media': 656 break; 657 default: 658 return '[unknown %s type]'; 659 break; 660 } 661 return compact('accesskey', 'type', 'id', 'method', 'params'); 662} 663 664/** 665 * Wrapper around tpl_button() and tpl_actionlink() 666 * 667 * @author Anika Henke <anika@selfthinker.org> 668 */ 669function tpl_action($type,$link=0,$wrapper=false,$return=false,$pre='',$suf='',$inner='') { 670 $out = ''; 671 if ($link) $out .= tpl_actionlink($type,$pre,$suf,$inner,1); 672 else $out .= tpl_button($type,1); 673 if ($out && $wrapper) $out = "<$wrapper>$out</$wrapper>"; 674 675 if ($return) return $out; 676 print $out; 677 return $out ? true : false; 678} 679 680/** 681 * Print the search form 682 * 683 * If the first parameter is given a div with the ID 'qsearch_out' will 684 * be added which instructs the ajax pagequicksearch to kick in and place 685 * its output into this div. The second parameter controls the propritary 686 * attribute autocomplete. If set to false this attribute will be set with an 687 * value of "off" to instruct the browser to disable it's own built in 688 * autocompletion feature (MSIE and Firefox) 689 * 690 * @author Andreas Gohr <andi@splitbrain.org> 691 */ 692function tpl_searchform($ajax=true,$autocomplete=true){ 693 global $lang; 694 global $ACT; 695 global $QUERY; 696 697 // don't print the search form if search action has been disabled 698 if (!actionOk('search')) return false; 699 700 print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search" method="get"><div class="no">'; 701 print '<input type="hidden" name="do" value="search" />'; 702 print '<input type="text" '; 703 if($ACT == 'search') print 'value="'.htmlspecialchars($QUERY).'" '; 704 if(!$autocomplete) print 'autocomplete="off" '; 705 print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />'; 706 print '<input type="submit" value="'.$lang['btn_search'].'" class="button" title="'.$lang['btn_search'].'" />'; 707 if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>'; 708 print '</div></form>'; 709 return true; 710} 711 712/** 713 * Print the breadcrumbs trace 714 * 715 * @author Andreas Gohr <andi@splitbrain.org> 716 */ 717function tpl_breadcrumbs($sep='•'){ 718 global $lang; 719 global $conf; 720 721 //check if enabled 722 if(!$conf['breadcrumbs']) return false; 723 724 $crumbs = breadcrumbs(); //setup crumb trace 725 726 //reverse crumborder in right-to-left mode, add RLM character to fix heb/eng display mixups 727 if($lang['direction'] == 'rtl') { 728 $crumbs = array_reverse($crumbs,true); 729 $crumbs_sep = ' ‏<span class="bcsep">'.$sep.'</span>‏ '; 730 } else { 731 $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> '; 732 } 733 734 //render crumbs, highlight the last one 735 print '<span class="bchead">'.$lang['breadcrumb'].':</span>'; 736 $last = count($crumbs); 737 $i = 0; 738 foreach ($crumbs as $id => $name){ 739 $i++; 740 echo $crumbs_sep; 741 if ($i == $last) print '<span class="curid">'; 742 tpl_link(wl($id),hsc($name),'class="breadcrumbs" title="'.$id.'"'); 743 if ($i == $last) print '</span>'; 744 } 745 return true; 746} 747 748/** 749 * Hierarchical breadcrumbs 750 * 751 * This code was suggested as replacement for the usual breadcrumbs. 752 * It only makes sense with a deep site structure. 753 * 754 * @author Andreas Gohr <andi@splitbrain.org> 755 * @author Nigel McNie <oracle.shinoda@gmail.com> 756 * @author Sean Coates <sean@caedmon.net> 757 * @author <fredrik@averpil.com> 758 * @todo May behave strangely in RTL languages 759 */ 760function tpl_youarehere($sep=' » '){ 761 global $conf; 762 global $ID; 763 global $lang; 764 765 // check if enabled 766 if(!$conf['youarehere']) return false; 767 768 $parts = explode(':', $ID); 769 $count = count($parts); 770 771 echo '<span class="bchead">'.$lang['youarehere'].': </span>'; 772 773 // always print the startpage 774 tpl_pagelink(':'.$conf['start']); 775 776 // print intermediate namespace links 777 $part = ''; 778 for($i=0; $i<$count - 1; $i++){ 779 $part .= $parts[$i].':'; 780 $page = $part; 781 if ($page == $conf['start']) continue; // Skip startpage 782 783 // output 784 echo $sep; 785 tpl_pagelink($page); 786 } 787 788 // print current page, skipping start page, skipping for namespace index 789 resolve_pageid('',$page,$exists); 790 if(isset($page) && $page==$part.$parts[$i]) return; 791 $page = $part.$parts[$i]; 792 if($page == $conf['start']) return; 793 echo $sep; 794 tpl_pagelink($page); 795 return true; 796} 797 798/** 799 * Print info if the user is logged in 800 * and show full name in that case 801 * 802 * Could be enhanced with a profile link in future? 803 * 804 * @author Andreas Gohr <andi@splitbrain.org> 805 */ 806function tpl_userinfo(){ 807 global $lang; 808 global $INFO; 809 if(isset($_SERVER['REMOTE_USER'])){ 810 print $lang['loggedinas'].': '.hsc($INFO['userinfo']['name']).' ('.hsc($_SERVER['REMOTE_USER']).')'; 811 return true; 812 } 813 return false; 814} 815 816/** 817 * Print some info about the current page 818 * 819 * @author Andreas Gohr <andi@splitbrain.org> 820 */ 821function tpl_pageinfo($ret=false){ 822 global $conf; 823 global $lang; 824 global $INFO; 825 global $ID; 826 827 // return if we are not allowed to view the page 828 if (!auth_quickaclcheck($ID)) { return false; } 829 830 // prepare date and path 831 $fn = $INFO['filepath']; 832 if(!$conf['fullpath']){ 833 if($INFO['rev']){ 834 $fn = str_replace(fullpath($conf['olddir']).'/','',$fn); 835 }else{ 836 $fn = str_replace(fullpath($conf['datadir']).'/','',$fn); 837 } 838 } 839 $fn = utf8_decodeFN($fn); 840 $date = dformat($INFO['lastmod']); 841 842 // print it 843 if($INFO['exists']){ 844 $out = ''; 845 $out .= $fn; 846 $out .= ' · '; 847 $out .= $lang['lastmod']; 848 $out .= ': '; 849 $out .= $date; 850 if($INFO['editor']){ 851 $out .= ' '.$lang['by'].' '; 852 $out .= editorinfo($INFO['editor']); 853 }else{ 854 $out .= ' ('.$lang['external_edit'].')'; 855 } 856 if($INFO['locked']){ 857 $out .= ' · '; 858 $out .= $lang['lockedby']; 859 $out .= ': '; 860 $out .= editorinfo($INFO['locked']); 861 } 862 if($ret){ 863 return $out; 864 }else{ 865 echo $out; 866 return true; 867 } 868 } 869 return false; 870} 871 872/** 873 * Prints or returns the name of the given page (current one if none given). 874 * 875 * If useheading is enabled this will use the first headline else 876 * the given ID is used. 877 * 878 * @author Andreas Gohr <andi@splitbrain.org> 879 */ 880function tpl_pagetitle($id=null, $ret=false){ 881 global $conf; 882 if(is_null($id)){ 883 global $ID; 884 $id = $ID; 885 } 886 887 $name = $id; 888 if (useHeading('navigation')) { 889 $title = p_get_first_heading($id); 890 if ($title) $name = $title; 891 } 892 893 if ($ret) { 894 return hsc($name); 895 } else { 896 print hsc($name); 897 return true; 898 } 899} 900 901/** 902 * Returns the requested EXIF/IPTC tag from the current image 903 * 904 * If $tags is an array all given tags are tried until a 905 * value is found. If no value is found $alt is returned. 906 * 907 * Which texts are known is defined in the functions _exifTagNames 908 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC 909 * to the names of the latter one) 910 * 911 * Only allowed in: detail.php 912 * 913 * @author Andreas Gohr <andi@splitbrain.org> 914 */ 915function tpl_img_getTag($tags,$alt='',$src=null){ 916 // Init Exif Reader 917 global $SRC; 918 919 if(is_null($src)) $src = $SRC; 920 921 static $meta = null; 922 if(is_null($meta)) $meta = new JpegMeta($src); 923 if($meta === false) return $alt; 924 $info = $meta->getField($tags); 925 if($info == false) return $alt; 926 return $info; 927} 928 929/** 930 * Prints the image with a link to the full sized version 931 * 932 * Only allowed in: detail.php 933 * 934 * @param $maxwidth int - maximal width of the image 935 * @param $maxheight int - maximal height of the image 936 * @param $link bool - link to the orginal size? 937 * @param $params array - additional image attributes 938 */ 939function tpl_img($maxwidth=0,$maxheight=0,$link=true,$params=null){ 940 global $IMG; 941 $w = tpl_img_getTag('File.Width'); 942 $h = tpl_img_getTag('File.Height'); 943 944 //resize to given max values 945 $ratio = 1; 946 if($w >= $h){ 947 if($maxwidth && $w >= $maxwidth){ 948 $ratio = $maxwidth/$w; 949 }elseif($maxheight && $h > $maxheight){ 950 $ratio = $maxheight/$h; 951 } 952 }else{ 953 if($maxheight && $h >= $maxheight){ 954 $ratio = $maxheight/$h; 955 }elseif($maxwidth && $w > $maxwidth){ 956 $ratio = $maxwidth/$w; 957 } 958 } 959 if($ratio){ 960 $w = floor($ratio*$w); 961 $h = floor($ratio*$h); 962 } 963 964 //prepare URLs 965 $url=ml($IMG,array('cache'=>$_REQUEST['cache']),true,'&'); 966 $src=ml($IMG,array('cache'=>$_REQUEST['cache'],'w'=>$w,'h'=>$h),true,'&'); 967 968 //prepare attributes 969 $alt=tpl_img_getTag('Simple.Title'); 970 if(is_null($params)){ 971 $p = array(); 972 }else{ 973 $p = $params; 974 } 975 if($w) $p['width'] = $w; 976 if($h) $p['height'] = $h; 977 $p['class'] = 'img_detail'; 978 if($alt){ 979 $p['alt'] = $alt; 980 $p['title'] = $alt; 981 }else{ 982 $p['alt'] = ''; 983 } 984 $p['src'] = $src; 985 986 $data = array('url'=>($link?$url:null), 'params'=>$p); 987 return trigger_event('TPL_IMG_DISPLAY',$data,'_tpl_img_action',true); 988} 989 990/** 991 * Default action for TPL_IMG_DISPLAY 992 */ 993function _tpl_img_action($data, $param=null) { 994 global $lang; 995 $p = buildAttributes($data['params']); 996 997 if($data['url']) print '<a href="'.hsc($data['url']).'" title="'.$lang['mediaview'].'">'; 998 print '<img '.$p.'/>'; 999 if($data['url']) print '</a>'; 1000 return true; 1001} 1002 1003/** 1004 * This function inserts a small gif which in reality is the indexer function. 1005 * 1006 * Should be called somewhere at the very end of the main.php 1007 * template 1008 */ 1009function tpl_indexerWebBug(){ 1010 global $ID; 1011 1012 $p = array(); 1013 $p['src'] = DOKU_BASE.'lib/exe/indexer.php?id='.rawurlencode($ID). 1014 '&'.time(); 1015 $p['width'] = 2; //no more 1x1 px image because we live in times of ad blockers... 1016 $p['height'] = 1; 1017 $p['alt'] = ''; 1018 $att = buildAttributes($p); 1019 print "<img $att />"; 1020 return true; 1021} 1022 1023// configuration methods 1024/** 1025 * tpl_getConf($id) 1026 * 1027 * use this function to access template configuration variables 1028 */ 1029function tpl_getConf($id){ 1030 global $conf; 1031 static $tpl_configloaded = false; 1032 1033 $tpl = $conf['template']; 1034 1035 if (!$tpl_configloaded){ 1036 $tconf = tpl_loadConfig(); 1037 if ($tconf !== false){ 1038 foreach ($tconf as $key => $value){ 1039 if (isset($conf['tpl'][$tpl][$key])) continue; 1040 $conf['tpl'][$tpl][$key] = $value; 1041 } 1042 $tpl_configloaded = true; 1043 } 1044 } 1045 1046 return $conf['tpl'][$tpl][$id]; 1047} 1048 1049/** 1050 * tpl_loadConfig() 1051 * reads all template configuration variables 1052 * this function is automatically called by tpl_getConf() 1053 */ 1054function tpl_loadConfig(){ 1055 1056 $file = tpl_incdir().'/conf/default.php'; 1057 $conf = array(); 1058 1059 if (!@file_exists($file)) return false; 1060 1061 // load default config file 1062 include($file); 1063 1064 return $conf; 1065} 1066 1067// language methods 1068/** 1069 * tpl_getLang($id) 1070 * 1071 * use this function to access template language variables 1072 */ 1073function tpl_getLang($id){ 1074 static $lang = array(); 1075 1076 if (count($lang) === 0){ 1077 $path = tpl_incdir().'lang/'; 1078 1079 $lang = array(); 1080 1081 global $conf; // definitely don't invoke "global $lang" 1082 // don't include once 1083 @include($path.'en/lang.php'); 1084 if ($conf['lang'] != 'en') @include($path.$conf['lang'].'/lang.php'); 1085 } 1086 1087 return $lang[$id]; 1088} 1089 1090/** 1091 * prints the "main content" in the mediamanger popup 1092 * 1093 * Depending on the user's actions this may be a list of 1094 * files in a namespace, the meta editing dialog or 1095 * a message of referencing pages 1096 * 1097 * Only allowed in mediamanager.php 1098 * 1099 * @triggers MEDIAMANAGER_CONTENT_OUTPUT 1100 * @param bool $fromajax - set true when calling this function via ajax 1101 * @author Andreas Gohr <andi@splitbrain.org> 1102 */ 1103function tpl_mediaContent($fromajax=false){ 1104 global $IMG; 1105 global $AUTH; 1106 global $INUSE; 1107 global $NS; 1108 global $JUMPTO; 1109 1110 if(is_array($_REQUEST['do'])){ 1111 $do = array_shift(array_keys($_REQUEST['do'])); 1112 }else{ 1113 $do = $_REQUEST['do']; 1114 } 1115 if(in_array($do,array('save','cancel'))) $do = ''; 1116 1117 if(!$do){ 1118 if($_REQUEST['edit']){ 1119 $do = 'metaform'; 1120 }elseif(is_array($INUSE)){ 1121 $do = 'filesinuse'; 1122 }else{ 1123 $do = 'filelist'; 1124 } 1125 } 1126 1127 // output the content pane, wrapped in an event. 1128 if(!$fromajax) ptln('<div id="media__content">'); 1129 $data = array( 'do' => $do); 1130 $evt = new Doku_Event('MEDIAMANAGER_CONTENT_OUTPUT', $data); 1131 if ($evt->advise_before()) { 1132 $do = $data['do']; 1133 if($do == 'filesinuse'){ 1134 media_filesinuse($INUSE,$IMG); 1135 }elseif($do == 'filelist'){ 1136 media_filelist($NS,$AUTH,$JUMPTO); 1137 }elseif($do == 'searchlist'){ 1138 media_searchlist($_REQUEST['q'],$NS,$AUTH); 1139 }else{ 1140 msg('Unknown action '.hsc($do),-1); 1141 } 1142 } 1143 $evt->advise_after(); 1144 unset($evt); 1145 if(!$fromajax) ptln('</div>'); 1146 1147} 1148 1149/** 1150 * Prints the central column in full-screen media manager 1151 * Depending on the opened tab this may be a list of 1152 * files in a namespace, upload form or search form 1153 * 1154 * @author Kate Arzamastseva <pshns@ukr.net> 1155 */ 1156function tpl_mediaFileList(){ 1157 global $AUTH; 1158 global $NS; 1159 global $JUMPTO; 1160 global $lang; 1161 1162 $opened_tab = $_REQUEST['tab_files']; 1163 if (!$opened_tab || !in_array($opened_tab, array('files', 'upload', 'search'))) $opened_tab = 'files'; 1164 if ($_REQUEST['mediado'] == 'update') $opened_tab = 'upload'; 1165 1166 echo '<h2 class="a11y">' . $lang['mediaselect'] . '</h2>'.NL; 1167 1168 media_tabs_files($opened_tab); 1169 1170 echo '<div class="panelHeader">'.NL; 1171 echo '<h3>'; 1172 $tabTitle = ($NS) ? $NS : '['.$lang['mediaroot'].']'; 1173 printf($lang['media_' . $opened_tab], '<strong>'.$tabTitle.'</strong>'); 1174 echo '</h3>'.NL; 1175 if ($opened_tab === 'search' || $opened_tab === 'files') { 1176 media_tab_files_options(); 1177 } 1178 echo '</div>'.NL; 1179 1180 echo '<div class="panelContent">'.NL; 1181 if ($opened_tab == 'files') { 1182 media_tab_files($NS,$AUTH,$JUMPTO); 1183 } elseif ($opened_tab == 'upload') { 1184 media_tab_upload($NS,$AUTH,$JUMPTO); 1185 } elseif ($opened_tab == 'search') { 1186 media_tab_search($NS,$AUTH); 1187 } 1188 echo '</div>'.NL; 1189} 1190 1191/** 1192 * Prints the third column in full-screen media manager 1193 * Depending on the opened tab this may be details of the 1194 * selected file, the meta editing dialog or 1195 * list of file revisions 1196 * 1197 * @author Kate Arzamastseva <pshns@ukr.net> 1198 */ 1199function tpl_mediaFileDetails($image, $rev){ 1200 global $AUTH, $NS, $conf, $DEL, $lang; 1201 1202 $removed = (!file_exists(mediaFN($image)) && file_exists(mediaMetaFN($image, '.changes')) && $conf['mediarevisions']); 1203 if (!$image || (!file_exists(mediaFN($image)) && !$removed) || $DEL) return ''; 1204 if ($rev && !file_exists(mediaFN($image, $rev))) $rev = false; 1205 if (isset($NS) && getNS($image) != $NS) return ''; 1206 $do = $_REQUEST['mediado']; 1207 1208 $opened_tab = $_REQUEST['tab_details']; 1209 1210 $tab_array = array('view'); 1211 list($ext, $mime) = mimetype($image); 1212 if ($mime == 'image/jpeg') { 1213 $tab_array[] = 'edit'; 1214 } 1215 if ($conf['mediarevisions']) { 1216 $tab_array[] = 'history'; 1217 } 1218 1219 if (!$opened_tab || !in_array($opened_tab, $tab_array)) $opened_tab = 'view'; 1220 if ($_REQUEST['edit']) $opened_tab = 'edit'; 1221 if ($do == 'restore') $opened_tab = 'view'; 1222 1223 media_tabs_details($image, $opened_tab); 1224 1225 echo '<div class="panelHeader"><h3>'; 1226 list($ext,$mime,$dl) = mimetype($image,false); 1227 $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); 1228 $class = 'select mediafile mf_'.$class; 1229 $tabTitle = '<strong class="'.$class.'"><a href="'.ml($image).'" title="'.$lang['mediaview'].'">'.$image.'</a>'.'</strong>'; 1230 if ($opened_tab === 'view' && $rev) { 1231 printf($lang['media_viewold'], $tabTitle, dformat($rev)); 1232 } else { 1233 printf($lang['media_' . $opened_tab], $tabTitle); 1234 } 1235 1236 echo '</h3></div>'.NL; 1237 1238 echo '<div class="panelContent">'.NL; 1239 1240 if ($opened_tab == 'view') { 1241 media_tab_view($image, $NS, $AUTH, $rev); 1242 1243 } elseif ($opened_tab == 'edit' && !$removed) { 1244 media_tab_edit($image, $NS, $AUTH); 1245 1246 } elseif ($opened_tab == 'history' && $conf['mediarevisions']) { 1247 media_tab_history($image,$NS,$AUTH); 1248 } 1249 1250 echo '</div>'.NL; 1251} 1252 1253/** 1254 * prints the namespace tree in the mediamanger popup 1255 * 1256 * Only allowed in mediamanager.php 1257 * 1258 * @author Andreas Gohr <andi@splitbrain.org> 1259 */ 1260function tpl_mediaTree(){ 1261 global $NS; 1262 ptln('<div id="media__tree">'); 1263 media_nstree($NS); 1264 ptln('</div>'); 1265} 1266 1267 1268/** 1269 * Print a dropdown menu with all DokuWiki actions 1270 * 1271 * Note: this will not use any pretty URLs 1272 * 1273 * @author Andreas Gohr <andi@splitbrain.org> 1274 */ 1275function tpl_actiondropdown($empty='',$button='>'){ 1276 global $ID; 1277 global $INFO; 1278 global $REV; 1279 global $ACT; 1280 global $conf; 1281 global $lang; 1282 global $auth; 1283 1284 echo '<form action="' . DOKU_SCRIPT . '" method="post" accept-charset="utf-8">'; 1285 echo '<div class="no">'; 1286 echo '<input type="hidden" name="id" value="'.$ID.'" />'; 1287 if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />'; 1288 echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'; 1289 1290 echo '<select name="do" class="edit quickselect">'; 1291 echo '<option value="">'.$empty.'</option>'; 1292 1293 echo '<optgroup label="'.$lang['page_tools'].'">'; 1294 $act = tpl_get_action('edit'); 1295 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1296 1297 $act = tpl_get_action('revert'); 1298 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1299 1300 $act = tpl_get_action('revisions'); 1301 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1302 1303 $act = tpl_get_action('backlink'); 1304 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1305 1306 $act = tpl_get_action('subscribe'); 1307 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1308 echo '</optgroup>'; 1309 1310 echo '<optgroup label="'.$lang['site_tools'].'">'; 1311 $act = tpl_get_action('recent'); 1312 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1313 1314 $act = tpl_get_action('media'); 1315 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1316 1317 $act = tpl_get_action('index'); 1318 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1319 echo '</optgroup>'; 1320 1321 echo '<optgroup label="'.$lang['user_tools'].'">'; 1322 $act = tpl_get_action('login'); 1323 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1324 1325 $act = tpl_get_action('register'); 1326 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1327 1328 $act = tpl_get_action('profile'); 1329 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1330 1331 $act = tpl_get_action('admin'); 1332 if($act) echo '<option value="'.$act['params']['do'].'">'.$lang['btn_'.$act['type']].'</option>'; 1333 echo '</optgroup>'; 1334 1335 echo '</select>'; 1336 echo '<input type="submit" value="'.$button.'" />'; 1337 echo '</div>'; 1338 echo '</form>'; 1339} 1340 1341/** 1342 * Print a informational line about the used license 1343 * 1344 * @author Andreas Gohr <andi@splitbrain.org> 1345 * @param string $img - print image? (|button|badge) 1346 * @param bool $return - when true don't print, but return HTML 1347 * @param bool $wrap - wrap in div with class="license"? 1348 */ 1349function tpl_license($img='badge',$imgonly=false,$return=false,$wrap=true){ 1350 global $license; 1351 global $conf; 1352 global $lang; 1353 if(!$conf['license']) return ''; 1354 if(!is_array($license[$conf['license']])) return ''; 1355 $lic = $license[$conf['license']]; 1356 $target = ($conf['target']['extern']) ? ' target="'.$conf['target']['extern'].'"' : ''; 1357 1358 $out = ''; 1359 if($wrap) $out .= '<div class="license">'; 1360 if($img){ 1361 $src = license_img($img); 1362 if($src){ 1363 $out .= '<a href="'.$lic['url'].'" rel="license"'.$target; 1364 $out .= '><img src="'.DOKU_BASE.$src.'" alt="'.$lic['name'].'" /></a>'; 1365 if(!$imgonly) $out .= ' '; 1366 } 1367 } 1368 if(!$imgonly) { 1369 $out .= $lang['license'].' '; 1370 $out .= '<a href="'.$lic['url'].'" rel="license" class="urlextern"'.$target; 1371 $out .= '>'.$lic['name'].'</a>'; 1372 } 1373 if($wrap) $out .= '</div>'; 1374 1375 if($return) return $out; 1376 echo $out; 1377} 1378 1379 1380/** 1381 * Includes the rendered XHTML of a given page 1382 * 1383 * This function is useful to populate sidebars or similar features in a 1384 * template 1385 */ 1386function tpl_include_page($pageid,$print=true){ 1387 global $ID; 1388 global $TOC; 1389 $oldid = $ID; 1390 $oldtoc = $TOC; 1391 $html = p_wiki_xhtml($pageid,'',false); 1392 $ID = $oldid; 1393 $TOC = $oldtoc; 1394 1395 if(!$print) return $html; 1396 echo $html; 1397 return $html; 1398} 1399 1400/** 1401 * Include the sidebar, will check current namespaces first 1402 */ 1403function tpl_sidebar($print=true){ 1404 global $conf; 1405 1406 $sidebar = page_findnearest($conf['sidebar']); 1407 if($sidebar) return tpl_include_page($sidebar, $print); 1408 return ''; 1409} 1410 1411/** 1412 * Display the subscribe form 1413 * 1414 * @author Adrian Lang <lang@cosmocode.de> 1415 */ 1416function tpl_subscribe() { 1417 global $INFO; 1418 global $ID; 1419 global $lang; 1420 global $conf; 1421 $stime_days = $conf['subscribe_time']/60/60/24; 1422 1423 echo p_locale_xhtml('subscr_form'); 1424 echo '<h2>' . $lang['subscr_m_current_header'] . '</h2>'; 1425 echo '<div class="level2">'; 1426 if ($INFO['subscribed'] === false) { 1427 echo '<p>' . $lang['subscr_m_not_subscribed'] . '</p>'; 1428 } else { 1429 echo '<ul>'; 1430 foreach($INFO['subscribed'] as $sub) { 1431 echo '<li><div class="li">'; 1432 if ($sub['target'] !== $ID) { 1433 echo '<code class="ns">'.hsc(prettyprint_id($sub['target'])).'</code>'; 1434 } else { 1435 echo '<code class="page">'.hsc(prettyprint_id($sub['target'])).'</code>'; 1436 } 1437 $sstl = sprintf($lang['subscr_style_'.$sub['style']], $stime_days); 1438 if(!$sstl) $sstl = hsc($sub['style']); 1439 echo ' ('.$sstl.') '; 1440 1441 echo '<a href="' . wl($ID, 1442 array('do'=>'subscribe', 1443 'sub_target'=>$sub['target'], 1444 'sub_style'=>$sub['style'], 1445 'sub_action'=>'unsubscribe', 1446 'sectok' => getSecurityToken())) . 1447 '" class="unsubscribe">'.$lang['subscr_m_unsubscribe'] . 1448 '</a></div></li>'; 1449 } 1450 echo '</ul>'; 1451 } 1452 echo '</div>'; 1453 1454 // Add new subscription form 1455 echo '<h2>' . $lang['subscr_m_new_header'] . '</h2>'; 1456 echo '<div class="level2">'; 1457 $ns = getNS($ID).':'; 1458 $targets = array( 1459 $ID => '<code class="page">'.prettyprint_id($ID).'</code>', 1460 $ns => '<code class="ns">'.prettyprint_id($ns).'</code>', 1461 ); 1462 $styles = array( 1463 'every' => $lang['subscr_style_every'], 1464 'digest' => sprintf($lang['subscr_style_digest'], $stime_days), 1465 'list' => sprintf($lang['subscr_style_list'], $stime_days), 1466 ); 1467 1468 $form = new Doku_Form(array('id' => 'subscribe__form')); 1469 $form->startFieldset($lang['subscr_m_subscribe']); 1470 $form->addRadioSet('sub_target', $targets); 1471 $form->startFieldset($lang['subscr_m_receive']); 1472 $form->addRadioSet('sub_style', $styles); 1473 $form->addHidden('sub_action', 'subscribe'); 1474 $form->addHidden('do', 'subscribe'); 1475 $form->addHidden('id', $ID); 1476 $form->endFieldset(); 1477 $form->addElement(form_makeButton('submit', 'subscribe', $lang['subscr_m_subscribe'])); 1478 html_form('SUBSCRIBE', $form); 1479 echo '</div>'; 1480} 1481 1482/** 1483 * Tries to send already created content right to the browser 1484 * 1485 * Wraps around ob_flush() and flush() 1486 * 1487 * @author Andreas Gohr <andi@splitbrain.org> 1488 */ 1489function tpl_flush(){ 1490 ob_flush(); 1491 flush(); 1492} 1493 1494/** 1495 * Tries to find a ressource file in the given locations. 1496 * 1497 * If a given location starts with a colon it is assumed to be a media 1498 * file, otherwise it is assumed to be relative to the current template 1499 * 1500 * @param array $search locations to look at 1501 * @param bool $abs if to use absolute URL 1502 * @param arrayref $imginfo filled with getimagesize() 1503 * @author Andreas Gohr <andi@splitbrain.org> 1504 */ 1505function tpl_getMediaFile($search, $abs=false, &$imginfo=null){ 1506 // loop through candidates until a match was found: 1507 foreach($search as $img){ 1508 if(substr($img,0,1) == ':'){ 1509 $file = mediaFN($img); 1510 $ismedia = true; 1511 }else{ 1512 $file = tpl_incdir().$img; 1513 $ismedia = false; 1514 } 1515 1516 if(file_exists($file)) break; 1517 } 1518 1519 // fetch image data if requested 1520 if(!is_null($imginfo)){ 1521 $imginfo = getimagesize($file); 1522 } 1523 1524 // build URL 1525 if($ismedia){ 1526 $url = ml($img, '', true, '', $abs); 1527 }else{ 1528 $url = tpl_basedir().$img; 1529 if($abs) $url = DOKU_URL.substr($url, strlen(DOKU_REL)); 1530 } 1531 1532 return $url; 1533} 1534 1535/** 1536 * PHP include a file 1537 * 1538 * either from the conf directory if it exists, otherwise use 1539 * file in the template's root directory. 1540 * 1541 * The function honours config cascade settings and looks for the given 1542 * file next to the ´main´ config files, in the order protected, local, 1543 * default. 1544 * 1545 * Note: no escaping or sanity checking is done here. Never pass user input 1546 * to this function! 1547 * 1548 * @author Anika Henke <anika@selfthinker.org> 1549 * @author Andreas Gohr <andi@splitbrain.org> 1550 */ 1551function tpl_includeFile($file){ 1552 global $config_cascade; 1553 foreach (array('protected','local','default') as $config_group) { 1554 if (empty($config_cascade['main'][$config_group])) continue; 1555 foreach ($config_cascade['main'][$config_group] as $conf_file) { 1556 $dir = dirname($conf_file); 1557 if(file_exists("$dir/$file")){ 1558 include("$dir/$file"); 1559 return; 1560 } 1561 } 1562 } 1563 1564 // still here? try the template dir 1565 $file = tpl_incdir().$file; 1566 if(file_exists($file)){ 1567 include($file); 1568 } 1569} 1570 1571/** 1572 * Returns icon from data/media root directory if it exists, otherwise 1573 * the one in the template's image directory. 1574 * 1575 * @deprecated Use tpl_getMediaFile() instead 1576 * @author Anika Henke <anika@selfthinker.org> 1577 */ 1578function tpl_getFavicon($abs=false, $fileName='favicon.ico') { 1579 $look = array(":wiki:$fileName", ":$fileName", "images/$fileName"); 1580 return tpl_getMediaFile($look, $abs); 1581} 1582 1583/** 1584 * Returns <link> tag for various icon types (favicon|mobile|generic) 1585 * 1586 * @param array $types - list of icon types to display (favicon|mobile|generic) 1587 * @author Anika Henke <anika@selfthinker.org> 1588 */ 1589function tpl_favicon($types=array('favicon')) { 1590 1591 $return = ''; 1592 1593 foreach ($types as $type) { 1594 switch($type) { 1595 case 'favicon': 1596 $look = array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico'); 1597 $return .= '<link rel="shortcut icon" href="'.tpl_getMediaFile($look).'" />'.NL; 1598 break; 1599 case 'mobile': 1600 $look = array(':wiki:apple-touch-icon.png', ':apple-touch-icon.png', 'images/apple-touch-icon.ico'); 1601 $return .= '<link rel="apple-touch-icon" href="'.tpl_getMediaFile($look).'" />'.NL; 1602 break; 1603 case 'generic': 1604 // ideal world solution, which doesn't work in any browser yet 1605 $look = array(':wiki:favicon.svg', ':favicon.svg', 'images/favicon.svg'); 1606 $return .= '<link rel="icon" href="'.tpl_getMediaFile($look).'" type="image/svg+xml" />'.NL; 1607 break; 1608 } 1609 } 1610 1611 return $return; 1612} 1613 1614/** 1615 * Prints full-screen media manager 1616 * 1617 * @author Kate Arzamastseva <pshns@ukr.net> 1618 */ 1619function tpl_media() { 1620 global $DEL, $NS, $IMG, $AUTH, $JUMPTO, $REV, $lang, $fullscreen, $conf; 1621 $fullscreen = true; 1622 require_once DOKU_INC.'lib/exe/mediamanager.php'; 1623 1624 if ($_REQUEST['image']) $image = cleanID($_REQUEST['image']); 1625 if (isset($IMG)) $image = $IMG; 1626 if (isset($JUMPTO)) $image = $JUMPTO; 1627 if (isset($REV) && !$JUMPTO) $rev = $REV; 1628 1629 echo '<div id="mediamanager__page">'.NL; 1630 echo '<h1>'.$lang['btn_media'].'</h1>'.NL; 1631 html_msgarea(); 1632 1633 echo '<div class="panel namespaces">'.NL; 1634 echo '<h2>'.$lang['namespaces'].'</h2>'.NL; 1635 echo '<div class="panelHeader">'; 1636 echo $lang['media_namespaces']; 1637 echo '</div>'.NL; 1638 1639 echo '<div class="panelContent" id="media__tree">'.NL; 1640 media_nstree($NS); 1641 echo '</div>'.NL; 1642 echo '</div>'.NL; 1643 1644 echo '<div class="panel filelist">'.NL; 1645 tpl_mediaFileList(); 1646 echo '</div>'.NL; 1647 1648 echo '<div class="panel file">'.NL; 1649 echo '<h2 class="a11y">'.$lang['media_file'].'</h2>'.NL; 1650 tpl_mediaFileDetails($image, $rev); 1651 echo '</div>'.NL; 1652 1653 echo '</div>'.NL; 1654} 1655 1656//Setup VIM: ex: et ts=4 : 1657 1658