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.'); 10require_once(DOKU_CONF.'dokuwiki.php'); 11 12/** 13 * Returns the path to the given template, uses 14 * default one if the custom version doesn't exist. 15 * 16 * @author Andreas Gohr <andi@splitbrain.org> 17 */ 18function template($tpl){ 19 global $conf; 20 21 if(@is_readable(DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$tpl)) 22 return DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$tpl; 23 24 return DOKU_INC.'lib/tpl/default/'.$tpl; 25} 26 27/** 28 * Print the content 29 * 30 * This function is used for printing all the usual content 31 * (defined by the global $ACT var) by calling the appropriate 32 * outputfunction(s) from html.php 33 * 34 * Everything that doesn't use the main template file isn't 35 * handled by this function. ACL stuff is not done here either. 36 * 37 * @author Andreas Gohr <andi@splitbrain.org> 38 */ 39function tpl_content($prependTOC=true) { 40 global $ACT; 41 global $INFO; 42 $INFO['prependTOC'] = $prependTOC; 43 44 ob_start(); 45 trigger_event('TPL_ACT_RENDER',$ACT,'tpl_content_core'); 46 $html_output = ob_get_clean(); 47 trigger_event('TPL_CONTENT_DISPLAY',$html_output,'ptln'); 48 49 return !empty($html_output); 50} 51 52function tpl_content_core(){ 53 global $ACT; 54 global $TEXT; 55 global $PRE; 56 global $SUF; 57 global $SUM; 58 global $IDX; 59 60 switch($ACT){ 61 case 'show': 62 html_show(); 63 break; 64 case 'preview': 65 html_edit($TEXT); 66 html_show($TEXT); 67 break; 68 case 'recover': 69 html_edit($TEXT); 70 break; 71 case 'edit': 72 html_edit(); 73 break; 74 case 'draft': 75 html_draft(); 76 break; 77 case 'wordblock': 78 html_edit($TEXT,'wordblock'); 79 break; 80 case 'search': 81 html_search(); 82 break; 83 case 'revisions': 84 $first = is_numeric($_REQUEST['first']) ? intval($_REQUEST['first']) : 0; 85 html_revisions($first); 86 break; 87 case 'diff': 88 html_diff(); 89 break; 90 case 'recent': 91 if (is_array($_REQUEST['first'])) { 92 $_REQUEST['first'] = array_keys($_REQUEST['first']); 93 $_REQUEST['first'] = $_REQUEST['first'][0]; 94 } 95 $first = is_numeric($_REQUEST['first']) ? intval($_REQUEST['first']) : 0; 96 html_recent($first); 97 break; 98 case 'index': 99 html_index($IDX); #FIXME can this be pulled from globals? is it sanitized correctly? 100 break; 101 case 'backlink': 102 html_backlinks(); 103 break; 104 case 'conflict': 105 html_conflict(con($PRE,$TEXT,$SUF),$SUM); 106 html_diff(con($PRE,$TEXT,$SUF),false); 107 break; 108 case 'locked': 109 html_locked(); 110 html_edit(); 111 break; 112 case 'login': 113 html_login(); 114 break; 115 case 'register': 116 html_register(); 117 break; 118 case 'resendpwd': 119 html_resendpwd(); 120 break; 121 case 'denied': 122 print p_locale_xhtml('denied'); 123 break; 124 case 'profile' : 125 html_updateprofile(); 126 break; 127 case 'admin': 128 tpl_admin(); 129 break; 130 default: 131 $evt = new Doku_Event('TPL_ACT_UNKNOWN',$ACT); 132 if ($evt->advise_before()) 133 msg("Failed to handle command: ".hsc($ACT),-1); 134 $evt->advise_after(); 135 unset($evt); 136 return false; 137 } 138 return true; 139} 140 141/** 142 * Places the TOC where the function is called 143 * 144 * If you use this you most probably want to call tpl_content with 145 * a false argument 146 * 147 * @author Andreas Gohr <andi@splitbrain.org> 148 */ 149function tpl_toc($return=false){ 150 global $TOC; 151 global $ACT; 152 global $ID; 153 global $REV; 154 global $INFO; 155 global $conf; 156 $toc = array(); 157 158 if(is_array($TOC)){ 159 // if a TOC was prepared in global scope, always use it 160 $toc = $TOC; 161 }elseif(($ACT == 'show' || substr($ACT,0,6) == 'export') && !$REV && $INFO['exists']){ 162 // get TOC from metadata, render if neccessary 163 $meta = p_get_metadata($ID, false, true); 164 if(isset($meta['internal']['toc'])){ 165 $tocok = $meta['internal']['toc']; 166 }else{ 167 $tocok = true; 168 } 169 $toc = $meta['description']['tableofcontents']; 170 if(!$tocok || !is_array($toc) || !$conf['tocminheads'] || count($toc) < $conf['tocminheads']){ 171 $toc = array(); 172 } 173 }elseif($ACT == 'admin'){ 174 // try to load admin plugin TOC FIXME: duplicates code from tpl_admin 175 $plugin = null; 176 if (!empty($_REQUEST['page'])) { 177 $pluginlist = plugin_list('admin'); 178 if (in_array($_REQUEST['page'], $pluginlist)) { 179 // attempt to load the plugin 180 $plugin =& plugin_load('admin',$_REQUEST['page']); 181 } 182 } 183 if ( ($plugin !== null) && 184 (!$plugin->forAdminOnly() || $INFO['isadmin']) ){ 185 $toc = $plugin->getTOC(); 186 $TOC = $toc; // avoid later rebuild 187 } 188 } 189 190 trigger_event('TPL_TOC_RENDER', $toc, NULL, false); 191 $html = html_TOC($toc); 192 if($return) return $html; 193 echo $html; 194} 195 196/** 197 * Handle the admin page contents 198 * 199 * @author Andreas Gohr <andi@splitbrain.org> 200 */ 201function tpl_admin(){ 202 global $INFO; 203 global $TOC; 204 205 $plugin = null; 206 if (!empty($_REQUEST['page'])) { 207 $pluginlist = plugin_list('admin'); 208 209 if (in_array($_REQUEST['page'], $pluginlist)) { 210 211 // attempt to load the plugin 212 $plugin =& plugin_load('admin',$_REQUEST['page']); 213 } 214 } 215 216 if ($plugin !== null){ 217 if($plugin->forAdminOnly() && !$INFO['isadmin']){ 218 msg('For admins only',-1); 219 html_admin(); 220 }else{ 221 if(!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet 222 if($INFO['prependTOC']) tpl_toc(); 223 $plugin->html(); 224 } 225 }else{ 226 html_admin(); 227 } 228 return true; 229} 230 231/** 232 * Print the correct HTML meta headers 233 * 234 * This has to go into the head section of your template. 235 * 236 * @triggers TPL_METAHEADER_OUTPUT 237 * @param boolean $alt Should feeds and alternative format links be added? 238 * @author Andreas Gohr <andi@splitbrain.org> 239 */ 240function tpl_metaheaders($alt=true){ 241 global $ID; 242 global $REV; 243 global $INFO; 244 global $ACT; 245 global $QUERY; 246 global $lang; 247 global $conf; 248 $it=2; 249 250 // prepare the head array 251 $head = array(); 252 253 254 // the usual stuff 255 $head['meta'][] = array( 'name'=>'generator', 'content'=>'DokuWiki '.getVersion() ); 256 $head['link'][] = array( 'rel'=>'search', 'type'=>'application/opensearchdescription+xml', 257 'href'=>DOKU_BASE.'lib/exe/opensearch.php', 'title'=>$conf['title'] ); 258 $head['link'][] = array( 'rel'=>'start', 'href'=>DOKU_BASE ); 259 if(actionOK('index')){ 260 $head['link'][] = array( 'rel'=>'contents', 'href'=> wl($ID,'do=index',false,'&'), 261 'title'=>$lang['btn_index'] ); 262 } 263 264 if($alt){ 265 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml', 266 'title'=>'Recent Changes', 'href'=>DOKU_BASE.'feed.php'); 267 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml', 268 'title'=>'Current Namespace', 269 'href'=>DOKU_BASE.'feed.php?mode=list&ns='.$INFO['namespace']); 270 if(($ACT == 'show' || $ACT == 'search') && $INFO['writable']){ 271 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/wiki', 272 'title'=>$lang['btn_edit'], 273 'href'=> wl($ID,'do=edit',false,'&')); 274 } 275 276 if($ACT == 'search'){ 277 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml', 278 'title'=>'Search Result', 279 'href'=>DOKU_BASE.'feed.php?mode=search&q='.$QUERY); 280 } 281 282 if(actionOK('export_xhtml')){ 283 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/html', 'title'=>'Plain HTML', 284 'href'=>exportlink($ID, 'xhtml', '', false, '&')); 285 } 286 287 if(actionOK('export_raw')){ 288 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/plain', 'title'=>'Wiki Markup', 289 'href'=>exportlink($ID, 'raw', '', false, '&')); 290 } 291 } 292 293 // setup robot tags apropriate for different modes 294 if( ($ACT=='show' || $ACT=='export_xhtml') && !$REV){ 295 if($INFO['exists']){ 296 //delay indexing: 297 if((time() - $INFO['lastmod']) >= $conf['indexdelay']){ 298 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow'); 299 }else{ 300 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow'); 301 } 302 }else{ 303 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,follow'); 304 } 305 }elseif(defined('DOKU_MEDIADETAIL')){ 306 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow'); 307 }else{ 308 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow'); 309 } 310 311 // set metadata 312 if($ACT == 'show' || $ACT=='export_xhtml'){ 313 // date of modification 314 if($REV){ 315 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$REV)); 316 }else{ 317 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$INFO['lastmod'])); 318 } 319 320 // keywords (explicit or implicit) 321 if(!empty($INFO['meta']['subject'])){ 322 $head['meta'][] = array( 'name'=>'keywords', 'content'=>join(',',$INFO['meta']['subject'])); 323 }else{ 324 $head['meta'][] = array( 'name'=>'keywords', 'content'=>str_replace(':',',',$ID)); 325 } 326 } 327 328 // load stylesheets 329 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'all', 'type'=>'text/css', 330 'href'=>DOKU_BASE.'lib/exe/css.php?s=all&t='.$conf['template']); 331 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'screen', 'type'=>'text/css', 332 'href'=>DOKU_BASE.'lib/exe/css.php?t='.$conf['template']); 333 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'print', 'type'=>'text/css', 334 'href'=>DOKU_BASE.'lib/exe/css.php?s=print&t='.$conf['template']); 335 336 // load javascript 337 $js_edit = ($ACT=='edit' || $ACT=='preview' || $ACT=='recover' || $ACT=='wordblock' ) ? 1 : 0; 338 $js_write = ($INFO['writable']) ? 1 : 0; 339 if(defined('DOKU_MEDIAMANAGER')){ 340 $js_edit = 1; 341 $js_write = 0; 342 } 343 if(($js_edit && $js_write) || defined('DOKU_MEDIAMANAGER')){ 344 $script = "NS='".$INFO['namespace']."';"; 345 if($conf['useacl'] && $_SERVER['REMOTE_USER']){ 346 require_once(DOKU_INC.'inc/toolbar.php'); 347 $script .= "SIG='".toolbar_signature()."';"; 348 } 349 $head['script'][] = array( 'type'=>'text/javascript', 'charset'=>'utf-8', 350 '_data'=> $script); 351 } 352 $head['script'][] = array( 'type'=>'text/javascript', 'charset'=>'utf-8', '_data'=>'', 353 'src'=>DOKU_BASE.'lib/exe/js.php?edit='.$js_edit.'&write='.$js_write); 354 355 // trigger event here 356 trigger_event('TPL_METAHEADER_OUTPUT',$head,'_tpl_metaheaders_action',true); 357 return true; 358} 359 360/** 361 * prints the array build by tpl_metaheaders 362 * 363 * $data is an array of different header tags. Each tag can have multiple 364 * instances. Attributes are given as key value pairs. Values will be HTML 365 * encoded automatically so they should be provided as is in the $data array. 366 * 367 * For tags having a body attribute specify the the body data in the special 368 * attribute '_data'. This field will NOT BE ESCAPED automatically. 369 * 370 * @author Andreas Gohr <andi@splitbrain.org> 371 */ 372function _tpl_metaheaders_action($data){ 373 foreach($data as $tag => $inst){ 374 foreach($inst as $attr){ 375 echo '<',$tag,' ',buildAttributes($attr); 376 if(isset($attr['_data'])){ 377 if($tag == 'script' && $attr['_data']) 378 $attr['_data'] = "<!--//--><![CDATA[//><!--\n". 379 $attr['_data']. 380 "\n//--><!]]>"; 381 382 echo '>',$attr['_data'],'</',$tag,'>'; 383 }else{ 384 echo '/>'; 385 } 386 echo "\n"; 387 } 388 } 389} 390 391/** 392 * Print a link 393 * 394 * Just builds a link. 395 * 396 * @author Andreas Gohr <andi@splitbrain.org> 397 */ 398function tpl_link($url,$name,$more=''){ 399 print '<a href="'.$url.'" '; 400 if ($more) print ' '.$more; 401 print ">$name</a>"; 402 return true; 403} 404 405/** 406 * Prints a link to a WikiPage 407 * 408 * Wrapper around html_wikilink 409 * 410 * @author Andreas Gohr <andi@splitbrain.org> 411 */ 412function tpl_pagelink($id,$name=NULL){ 413 print html_wikilink($id,$name); 414 return true; 415} 416 417/** 418 * get the parent page 419 * 420 * Tries to find out which page is parent. 421 * returns false if none is available 422 * 423 * @author Andreas Gohr <andi@splitbrain.org> 424 */ 425function tpl_getparent($id){ 426 global $conf; 427 $parent = getNS($id).':'; 428 resolve_pageid('',$parent,$exists); 429 if($parent == $id) { 430 $pos = strrpos (getNS($id),':'); 431 $parent = substr($parent,0,$pos).':'; 432 resolve_pageid('',$parent,$exists); 433 if($parent == $id) return false; 434 } 435 return $parent; 436} 437 438/** 439 * Print one of the buttons 440 * 441 * Available Buttons are 442 * 443 * edit - edit/create/show/draft button 444 * history - old revisions 445 * recent - recent changes 446 * login - login/logout button - if ACL enabled 447 * profile - user profile button (if logged in) 448 * index - The index 449 * admin - admin page - if enough rights 450 * top - a back to top button 451 * back - a back to parent button - if available 452 * backlink - links to the list of backlinks 453 * subscription- subscribe/unsubscribe button 454 * 455 * @author Andreas Gohr <andi@splitbrain.org> 456 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 457 */ 458function tpl_button($type){ 459 global $ACT; 460 global $ID; 461 global $REV; 462 global $NS; 463 global $INFO; 464 global $conf; 465 global $auth; 466 467 // check disabled actions and fix the badly named ones 468 $ctype = $type; 469 if($type == 'history') $ctype='revisions'; 470 if(!actionOK($ctype)) return false; 471 472 switch($type){ 473 case 'edit': 474 #most complicated type - we need to decide on current action 475 if($ACT == 'show' || $ACT == 'search'){ 476 if($INFO['writable']){ 477 if(!empty($INFO['draft'])){ 478 echo html_btn('draft',$ID,'e',array('do' => 'draft'),'post'); 479 }else{ 480 if($INFO['exists']){ 481 echo html_btn('edit',$ID,'e',array('do' => 'edit','rev' => $REV),'post'); 482 }else{ 483 echo html_btn('create',$ID,'e',array('do' => 'edit','rev' => $REV),'post'); 484 } 485 } 486 }else{ 487 if(!actionOK('source')) return false; //pseudo action 488 echo html_btn('source',$ID,'v',array('do' => 'edit','rev' => $REV),'post'); 489 } 490 }else{ 491 echo html_btn('show',$ID,'v',array('do' => 'show')); 492 } 493 return true; 494 case 'history': 495 if(!actionOK('revisions')) 496 return false; 497 print html_btn('revs',$ID,'o',array('do' => 'revisions')); 498 return true; 499 case 'recent': 500 if(!actionOK('recent')) 501 return false; 502 print html_btn('recent',$ID,'r',array('do' => 'recent')); 503 return true; 504 case 'index': 505 if(!actionOK('index')) 506 return false; 507 print html_btn('index',$ID,'x',array('do' => 'index')); 508 return true; 509 case 'back': 510 if ($parent = tpl_getparent($ID)) { 511 print html_btn('back',$parent,'b',array('do' => 'show')); 512 return true; 513 } 514 return false; 515 case 'top': 516 print html_topbtn(); 517 return true; 518 case 'login': 519 if($conf['useacl'] && $auth){ 520 if($_SERVER['REMOTE_USER']){ 521 print html_btn('logout',$ID,'',array('do' => 'logout', 'sectok' => getSecurityToken())); 522 }else{ 523 print html_btn('login',$ID,'',array('do' => 'login', 'sectok' => getSecurityToken())); 524 } 525 return true; 526 } 527 return false; 528 case 'admin': 529 if($INFO['ismanager']){ 530 print html_btn('admin',$ID,'',array('do' => 'admin')); 531 return true; 532 } 533 return false; 534 case 'subscribe': 535 case 'subscription': 536 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers'] == 1){ 537 if($_SERVER['REMOTE_USER']){ 538 if($INFO['subscribed']){ 539 if(!actionOK('unsubscribe')) 540 return false; 541 print html_btn('unsubscribe',$ID,'',array('do' => 'unsubscribe',)); 542 } else { 543 if(!actionOK('subscribe')) 544 return false; 545 print html_btn('subscribe',$ID,'',array('do' => 'subscribe',)); 546 } 547 if($type == 'subscribe') return true; 548 } 549 } 550 if($type == 'subscribe') return false; 551 // fall through for backward compatibility 552 case 'subscribens': 553 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers'] == 1){ 554 if($_SERVER['REMOTE_USER']){ 555 if($INFO['subscribedns']){ 556 if(!actionOK('unsubscribens')) 557 return false; 558 print html_btn('unsubscribens',$ID,'',array('do' => 'unsubscribens',)); 559 } else { 560 if(!actionOK('subscribens')) 561 return false; 562 print html_btn('subscribens',$ID,'',array('do' => 'subscribens',)); 563 } 564 return true; 565 } 566 } 567 return false; 568 case 'backlink': 569 if(!actionOK('backlink')) 570 return false; 571 print html_btn('backlink',$ID,'',array('do' => 'backlink')); 572 return true; 573 case 'profile': 574 if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $auth && 575 $auth->canDo('Profile') && ($ACT!='profile')){ 576 print html_btn('profile',$ID,'',array('do' => 'profile')); 577 return true; 578 } 579 return false; 580 default: 581 print '[unknown button type]'; 582 return true; 583 } 584} 585 586/** 587 * Like the action buttons but links 588 * 589 * Available links are 590 * 591 * edit - edit/create/show link 592 * history - old revisions 593 * recent - recent changes 594 * login - login/logout link - if ACL enabled 595 * profile - user profile link (if logged in) 596 * index - The index 597 * admin - admin page - if enough rights 598 * top - a back to top link 599 * back - a back to parent link - if available 600 * backlink - links to the list of backlinks 601 * subscribe/subscription - subscribe/unsubscribe link 602 * 603 * @author Andreas Gohr <andi@splitbrain.org> 604 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 605 * @see tpl_button 606 */ 607function tpl_actionlink($type,$pre='',$suf='',$inner=''){ 608 global $ID; 609 global $INFO; 610 global $REV; 611 global $ACT; 612 global $conf; 613 global $lang; 614 global $auth; 615 616 // check disabled actions and fix the badly named ones 617 $ctype = $type; 618 if($type == 'history') $ctype='revisions'; 619 if(!actionOK($ctype)) return false; 620 621 switch($type){ 622 case 'edit': 623 #most complicated type - we need to decide on current action 624 if($ACT == 'show' || $ACT == 'search'){ 625 if($INFO['writable']){ 626 if(!empty($INFO['draft'])) { 627 tpl_link(wl($ID,'do=draft'), 628 $pre.(($inner)?$inner:$lang['btn_draft']).$suf, 629 'class="action edit" accesskey="e" rel="nofollow"'); 630 } else { 631 if($INFO['exists']){ 632 tpl_link(wl($ID,'do=edit&rev='.$REV), 633 $pre.(($inner)?$inner:$lang['btn_edit']).$suf, 634 'class="action edit" accesskey="e" rel="nofollow"'); 635 }else{ 636 tpl_link(wl($ID,'do=edit&rev='.$REV), 637 $pre.(($inner)?$inner:$lang['btn_create']).$suf, 638 'class="action create" accesskey="e" rel="nofollow"'); 639 } 640 } 641 }else{ 642 if(!actionOK('source')) return false; //pseudo action 643 tpl_link(wl($ID,'do=edit&rev='.$REV), 644 $pre.(($inner)?$inner:$lang['btn_source']).$suf, 645 'class="action source" accesskey="v" rel="nofollow"'); 646 } 647 }else{ 648 tpl_link(wl($ID,'do=show'), 649 $pre.(($inner)?$inner:$lang['btn_show']).$suf, 650 'class="action show" accesskey="v" rel="nofollow"'); 651 } 652 return true; 653 case 'history': 654 if(!actionOK('revisions')) 655 return false; 656 tpl_link(wl($ID,'do=revisions'), 657 $pre.(($inner)?$inner:$lang['btn_revs']).$suf, 658 'class="action revisions" accesskey="o" rel="nofollow"'); 659 return true; 660 case 'recent': 661 if(!actionOK('recent')) 662 return false; 663 tpl_link(wl($ID,'do=recent'), 664 $pre.(($inner)?$inner:$lang['btn_recent']).$suf, 665 'class="action recent" accesskey="r" rel="nofollow"'); 666 return true; 667 case 'index': 668 if(!actionOK('index')) 669 return false; 670 tpl_link(wl($ID,'do=index'), 671 $pre.(($inner)?$inner:$lang['btn_index']).$suf, 672 'class="action index" accesskey="x" rel="nofollow"'); 673 return true; 674 case 'top': 675 print '<a href="#dokuwiki__top" class="action top" accesskey="x">'. 676 $pre.(($inner)?$inner:$lang['btn_top']).$suf.'</a>'; 677 return true; 678 case 'back': 679 if ($parent = tpl_getparent($ID)) { 680 tpl_link(wl($parent,'do=show'), 681 $pre.(($inner)?$inner:$lang['btn_back']).$suf, 682 'class="action back" accesskey="b" rel="nofollow"'); 683 return true; 684 } 685 return false; 686 case 'login': 687 if($conf['useacl'] && $auth){ 688 if($_SERVER['REMOTE_USER']){ 689 tpl_link(wl($ID,'do=logout&sectok='.getSecurityToken()), 690 $pre.(($inner)?$inner:$lang['btn_logout']).$suf, 691 'class="action logout" rel="nofollow"'); 692 }else{ 693 tpl_link(wl($ID,'do=login&sectok='.getSecurityToken()), 694 $pre.(($inner)?$inner:$lang['btn_login']).$suf, 695 'class="action login" rel="nofollow"'); 696 } 697 return true; 698 } 699 return false; 700 case 'admin': 701 if($INFO['ismanager']){ 702 tpl_link(wl($ID,'do=admin'), 703 $pre.(($inner)?$inner:$lang['btn_admin']).$suf, 704 'class="action admin" rel="nofollow"'); 705 return true; 706 } 707 return false; 708 case 'subscribe': 709 case 'subscription': 710 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers'] == 1){ 711 if($_SERVER['REMOTE_USER']){ 712 if($INFO['subscribed']) { 713 if(!actionOK('unsubscribe')) 714 return false; 715 tpl_link(wl($ID,'do=unsubscribe'), 716 $pre.(($inner)?$inner:$lang['btn_unsubscribe']).$suf, 717 'class="action unsubscribe" rel="nofollow"'); 718 } else { 719 if(!actionOK('subscribe')) 720 return false; 721 tpl_link(wl($ID,'do=subscribe'), 722 $pre.(($inner)?$inner:$lang['btn_subscribe']).$suf, 723 'class="action subscribe" rel="nofollow"'); 724 } 725 return true; 726 } 727 } 728 return false; 729 case 'subscribens': 730 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers'] == 1){ 731 if($_SERVER['REMOTE_USER']){ 732 if($INFO['subscribedns']) { 733 if(!actionOK('unsubscribens')) 734 return false; 735 tpl_link(wl($ID,'do=unsubscribens'), 736 $pre.(($inner)?$inner:$lang['btn_unsubscribens']).$suf, 737 'class="action unsubscribens" rel="nofollow"'); 738 } else { 739 if(!actionOK('subscribens')) 740 return false; 741 tpl_link(wl($ID,'do=subscribens'), 742 $pre.(($inner)?$inner:$lang['btn_subscribens']).$suf, 743 'class="action subscribens" rel="nofollow"'); 744 } 745 return true; 746 } 747 } 748 return false; 749 case 'backlink': 750 if(!actionOK('backlink')) 751 return false; 752 tpl_link(wl($ID,'do=backlink'), 753 $pre.(($inner)?$inner:$lang['btn_backlink']).$suf, 754 'class="action backlink" rel="nofollow"'); 755 return true; 756 case 'profile': 757 if($conf['useacl'] && $auth && $_SERVER['REMOTE_USER'] && 758 $auth->canDo('Profile') && ($ACT!='profile')){ 759 tpl_link(wl($ID,'do=profile'), 760 $pre.(($inner)?$inner:$lang['btn_profile']).$suf, 761 'class="action profile" rel="nofollow"'); 762 return true; 763 } 764 return false; 765 default: 766 print '[unknown link type]'; 767 return true; 768 } 769} 770 771/** 772 * Print the search form 773 * 774 * If the first parameter is given a div with the ID 'qsearch_out' will 775 * be added which instructs the ajax pagequicksearch to kick in and place 776 * its output into this div. The second parameter controls the propritary 777 * attribute autocomplete. If set to false this attribute will be set with an 778 * value of "off" to instruct the browser to disable it's own built in 779 * autocompletion feature (MSIE and Firefox) 780 * 781 * @author Andreas Gohr <andi@splitbrain.org> 782 */ 783function tpl_searchform($ajax=true,$autocomplete=true){ 784 global $lang; 785 global $ACT; 786 787 // don't print the search form if search action has been disabled 788 if (!actionOk('search')) return false; 789 790 print '<form action="'.wl().'" accept-charset="utf-8" class="search" id="dw__search"><div class="no">'; 791 print '<input type="hidden" name="do" value="search" />'; 792 print '<input type="text" '; 793 if($ACT == 'search') print 'value="'.htmlspecialchars($_REQUEST['id']).'" '; 794 if(!$autocomplete) print 'autocomplete="off" '; 795 print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[F]" />'; 796 print '<input type="submit" value="'.$lang['btn_search'].'" class="button" title="'.$lang['btn_search'].'" />'; 797 if($ajax) print '<div id="qsearch__out" class="ajax_qsearch JSpopup"></div>'; 798 print '</div></form>'; 799 return true; 800} 801 802/** 803 * Print the breadcrumbs trace 804 * 805 * @author Andreas Gohr <andi@splitbrain.org> 806 */ 807function tpl_breadcrumbs($sep='»'){ 808 global $lang; 809 global $conf; 810 811 //check if enabled 812 if(!$conf['breadcrumbs']) return false; 813 814 $crumbs = breadcrumbs(); //setup crumb trace 815 816 //reverse crumborder in right-to-left mode, add RLM character to fix heb/eng display mixups 817 if($lang['direction'] == 'rtl') { 818 $crumbs = array_reverse($crumbs,true); 819 $crumbs_sep = ' ‏<span class="bcsep">'.$sep.'</span>‏ '; 820 } else { 821 $crumbs_sep = ' <span class="bcsep">'.$sep.'</span> '; 822 } 823 824 //render crumbs, highlight the last one 825 print '<span class="bchead">'.$lang['breadcrumb'].':</span>'; 826 $last = count($crumbs); 827 $i = 0; 828 foreach ($crumbs as $id => $name){ 829 $i++; 830 echo $crumbs_sep; 831 if ($i == $last) print '<span class="curid">'; 832 tpl_link(wl($id),hsc($name),'class="breadcrumbs" title="'.$id.'"'); 833 if ($i == $last) print '</span>'; 834 } 835 return true; 836} 837 838/** 839 * Hierarchical breadcrumbs 840 * 841 * This code was suggested as replacement for the usual breadcrumbs. 842 * It only makes sense with a deep site structure. 843 * 844 * @author Andreas Gohr <andi@splitbrain.org> 845 * @author Nigel McNie <oracle.shinoda@gmail.com> 846 * @author Sean Coates <sean@caedmon.net> 847 * @author <fredrik@averpil.com> 848 * @todo May behave strangely in RTL languages 849 */ 850function tpl_youarehere($sep=' » '){ 851 global $conf; 852 global $ID; 853 global $lang; 854 855 // check if enabled 856 if(!$conf['youarehere']) return false; 857 858 $parts = explode(':', $ID); 859 $count = count($parts); 860 861 echo '<span class="bchead">'.$lang['youarehere'].': </span>'; 862 863 // always print the startpage 864 $title = useHeading('navigation') ? p_get_first_heading($conf['start']) : $conf['start']; 865 if(!$title) $title = $conf['start']; 866 tpl_link(wl($conf['start']),hsc($title),'title="'.$conf['start'].'"'); 867 868 // print intermediate namespace links 869 $part = ''; 870 for($i=0; $i<$count - 1; $i++){ 871 $part .= $parts[$i].':'; 872 $page = $part; 873 resolve_pageid('',$page,$exists); 874 if ($page == $conf['start']) continue; // Skip startpage 875 876 // output 877 echo $sep; 878 if($exists){ 879 $title = useHeading('navigation') ? p_get_first_heading($page) : $page; 880 if(!$title) $title = $parts[$i]; 881 tpl_link(wl($page),hsc($title),'title="'.$page.'"'); 882 }else{ 883 tpl_link(wl($page),$parts[$i],'title="'.$page.'" class="wikilink2" rel="nofollow"'); 884 } 885 } 886 887 // print current page, skipping start page, skipping for namespace index 888 if(isset($page) && $page==$part.$parts[$i]) return; 889 $page = $part.$parts[$i]; 890 if($page == $conf['start']) return; 891 echo $sep; 892 if(page_exists($page)){ 893 $title = useHeading('navigation') ? p_get_first_heading($page) : $page; 894 if(!$title) $title = $parts[$i]; 895 tpl_link(wl($page),hsc($title),'title="'.$page.'"'); 896 }else{ 897 tpl_link(wl($page),$parts[$i],'title="'.$page.'" class="wikilink2" rel="nofollow"'); 898 } 899 return true; 900} 901 902/** 903 * Print info if the user is logged in 904 * and show full name in that case 905 * 906 * Could be enhanced with a profile link in future? 907 * 908 * @author Andreas Gohr <andi@splitbrain.org> 909 */ 910function tpl_userinfo(){ 911 global $lang; 912 global $INFO; 913 if($_SERVER['REMOTE_USER']){ 914 print $lang['loggedinas'].': '.$INFO['userinfo']['name'].' ('.$_SERVER['REMOTE_USER'].')'; 915 return true; 916 } 917 return false; 918} 919 920/** 921 * Print some info about the current page 922 * 923 * @author Andreas Gohr <andi@splitbrain.org> 924 */ 925function tpl_pageinfo($ret=false){ 926 global $conf; 927 global $lang; 928 global $INFO; 929 global $REV; 930 global $ID; 931 932 // return if we are not allowed to view the page 933 if (!auth_quickaclcheck($ID)) { return false; } 934 935 // prepare date and path 936 $fn = $INFO['filepath']; 937 if(!$conf['fullpath']){ 938 if($REV){ 939 $fn = str_replace(fullpath($conf['olddir']).'/','',$fn); 940 }else{ 941 $fn = str_replace(fullpath($conf['datadir']).'/','',$fn); 942 } 943 } 944 $fn = utf8_decodeFN($fn); 945 $date = strftime($conf['dformat'],$INFO['lastmod']); 946 947 // print it 948 if($INFO['exists']){ 949 $out = ''; 950 $out .= $fn; 951 $out .= ' · '; 952 $out .= $lang['lastmod']; 953 $out .= ': '; 954 $out .= $date; 955 if($INFO['editor']){ 956 $out .= ' '.$lang['by'].' '; 957 $out .= editorinfo($INFO['editor']); 958 }else{ 959 $out .= ' ('.$lang['external_edit'].')'; 960 } 961 if($INFO['locked']){ 962 $out .= ' · '; 963 $out .= $lang['lockedby']; 964 $out .= ': '; 965 $out .= editorinfo($INFO['locked']); 966 } 967 if($ret){ 968 return $out; 969 }else{ 970 echo $out; 971 return true; 972 } 973 } 974 return false; 975} 976 977/** 978 * Prints or returns the name of the given page (current one if none given). 979 * 980 * If useheading is enabled this will use the first headline else 981 * the given ID is used. 982 * 983 * @author Andreas Gohr <andi@splitbrain.org> 984 */ 985function tpl_pagetitle($id=null, $ret=false){ 986 global $conf; 987 if(is_null($id)){ 988 global $ID; 989 $id = $ID; 990 } 991 992 $name = $id; 993 if (useHeading('navigation')) { 994 $title = p_get_first_heading($id); 995 if ($title) $name = $title; 996 } 997 998 if ($ret) { 999 return hsc($name); 1000 } else { 1001 print hsc($name); 1002 return true; 1003 } 1004} 1005 1006/** 1007 * Returns the requested EXIF/IPTC tag from the current image 1008 * 1009 * If $tags is an array all given tags are tried until a 1010 * value is found. If no value is found $alt is returned. 1011 * 1012 * Which texts are known is defined in the functions _exifTagNames 1013 * and _iptcTagNames() in inc/jpeg.php (You need to prepend IPTC 1014 * to the names of the latter one) 1015 * 1016 * Only allowed in: detail.php 1017 * 1018 * @author Andreas Gohr <andi@splitbrain.org> 1019 */ 1020function tpl_img_getTag($tags,$alt='',$src=null){ 1021 // Init Exif Reader 1022 global $SRC; 1023 1024 if(is_null($src)) $src = $SRC; 1025 1026 static $meta = null; 1027 if(is_null($meta)) $meta = new JpegMeta($src); 1028 if($meta === false) return $alt; 1029 $info = $meta->getField($tags); 1030 if($info == false) return $alt; 1031 return $info; 1032} 1033 1034/** 1035 * Prints the image with a link to the full sized version 1036 * 1037 * Only allowed in: detail.php 1038 */ 1039function tpl_img($maxwidth=0,$maxheight=0){ 1040 global $IMG; 1041 $w = tpl_img_getTag('File.Width'); 1042 $h = tpl_img_getTag('File.Height'); 1043 1044 //resize to given max values 1045 $ratio = 1; 1046 if($w >= $h){ 1047 if($maxwidth && $w >= $maxwidth){ 1048 $ratio = $maxwidth/$w; 1049 }elseif($maxheight && $h > $maxheight){ 1050 $ratio = $maxheight/$h; 1051 } 1052 }else{ 1053 if($maxheight && $h >= $maxheight){ 1054 $ratio = $maxheight/$h; 1055 }elseif($maxwidth && $w > $maxwidth){ 1056 $ratio = $maxwidth/$w; 1057 } 1058 } 1059 if($ratio){ 1060 $w = floor($ratio*$w); 1061 $h = floor($ratio*$h); 1062 } 1063 1064 //prepare URLs 1065 $url=ml($IMG,array('cache'=>$_REQUEST['cache'])); 1066 $src=ml($IMG,array('cache'=>$_REQUEST['cache'],'w'=>$w,'h'=>$h)); 1067 1068 //prepare attributes 1069 $alt=tpl_img_getTag('Simple.Title'); 1070 $p = array(); 1071 if($w) $p['width'] = $w; 1072 if($h) $p['height'] = $h; 1073 $p['class'] = 'img_detail'; 1074 if($alt){ 1075 $p['alt'] = $alt; 1076 $p['title'] = $alt; 1077 }else{ 1078 $p['alt'] = ''; 1079 } 1080 $p = buildAttributes($p); 1081 1082 print '<a href="'.$url.'">'; 1083 print '<img src="'.$src.'" '.$p.'/>'; 1084 print '</a>'; 1085 return true; 1086} 1087 1088/** 1089 * This function inserts a 1x1 pixel gif which in reality 1090 * is the inexer function. 1091 * 1092 * Should be called somewhere at the very end of the main.php 1093 * template 1094 */ 1095function tpl_indexerWebBug(){ 1096 global $ID; 1097 global $INFO; 1098 if(!$INFO['exists']) return false; 1099 1100 if(isHiddenPage($ID)) return false; //no need to index hidden pages 1101 1102 $p = array(); 1103 $p['src'] = DOKU_BASE.'lib/exe/indexer.php?id='.rawurlencode($ID). 1104 '&'.time(); 1105 $p['width'] = 1; 1106 $p['height'] = 1; 1107 $p['alt'] = ''; 1108 $att = buildAttributes($p); 1109 print "<img $att />"; 1110 return true; 1111} 1112 1113// configuration methods 1114/** 1115 * tpl_getConf($id) 1116 * 1117 * use this function to access template configuration variables 1118 */ 1119function tpl_getConf($id){ 1120 global $conf; 1121 global $tpl_configloaded; 1122 1123 $tpl = $conf['template']; 1124 1125 if (!$tpl_configloaded){ 1126 $tconf = tpl_loadConfig(); 1127 if ($tconf !== false){ 1128 foreach ($tconf as $key => $value){ 1129 if (isset($conf['tpl'][$tpl][$key])) continue; 1130 $conf['tpl'][$tpl][$key] = $value; 1131 } 1132 $tpl_configloaded = true; 1133 } 1134 } 1135 1136 return $conf['tpl'][$tpl][$id]; 1137} 1138 1139/** 1140 * tpl_loadConfig() 1141 * reads all template configuration variables 1142 * this function is automatically called by tpl_getConf() 1143 */ 1144function tpl_loadConfig(){ 1145 1146 $file = DOKU_TPLINC.'/conf/default.php'; 1147 $conf = array(); 1148 1149 if (!@file_exists($file)) return false; 1150 1151 // load default config file 1152 include($file); 1153 1154 return $conf; 1155} 1156 1157/** 1158 * prints the "main content" in the mediamanger popup 1159 * 1160 * Depending on the user's actions this may be a list of 1161 * files in a namespace, the meta editing dialog or 1162 * a message of referencing pages 1163 * 1164 * Only allowed in mediamanager.php 1165 * 1166 * @author Andreas Gohr <andi@splitbrain.org> 1167 */ 1168function tpl_mediaContent(){ 1169 global $IMG; 1170 global $AUTH; 1171 global $INUSE; 1172 global $NS; 1173 global $JUMPTO; 1174 1175 ptln('<div id="media__content">'); 1176 if($_REQUEST['edit']){ 1177 media_metaform($IMG,$AUTH); 1178 }elseif(is_array($INUSE)){ 1179 media_filesinuse($INUSE,$IMG); 1180 }else{ 1181 media_filelist($NS,$AUTH,$JUMPTO); 1182 } 1183 ptln('</div>'); 1184} 1185 1186/** 1187 * prints the namespace tree in the mediamanger popup 1188 * 1189 * Only allowed in mediamanager.php 1190 * 1191 * @author Andreas Gohr <andi@splitbrain.org> 1192 */ 1193function tpl_mediaTree(){ 1194 global $NS; 1195 1196 ptln('<div id="media__tree">'); 1197 media_nstree($NS); 1198 ptln('</div>'); 1199} 1200 1201 1202/** 1203 * Print a dropdown menu with all DokuWiki actions 1204 * 1205 * Note: this will not use any pretty URLs 1206 * 1207 * @author Andreas Gohr <andi@splitbrain.org> 1208 */ 1209function tpl_actiondropdown($empty='',$button='>'){ 1210 global $ID; 1211 global $INFO; 1212 global $REV; 1213 global $ACT; 1214 global $conf; 1215 global $lang; 1216 global $auth; 1217 1218 1219 echo '<form method="post" accept-charset="utf-8">'; #FIXME action 1220 echo '<input type="hidden" name="id" value="'.$ID.'" />'; 1221 if($REV) echo '<input type="hidden" name="rev" value="'.$REV.'" />'; 1222 echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'; 1223 1224 echo '<select name="do" id="action__selector" class="edit">'; 1225 echo '<option value="">'.$empty.'</option>'; 1226 1227 echo '<optgroup label=" — ">'; 1228 // 'edit' - most complicated type, we need to decide on current action 1229 if($ACT == 'show' || $ACT == 'search'){ 1230 if($INFO['writable']){ 1231 if(!empty($INFO['draft'])) { 1232 echo '<option value="edit">'.$lang['btn_draft'].'</option>'; 1233 } else { 1234 if($INFO['exists']){ 1235 echo '<option value="edit">'.$lang['btn_edit'].'</option>'; 1236 }else{ 1237 echo '<option value="edit">'.$lang['btn_create'].'</option>'; 1238 } 1239 } 1240 }else if(actionOK('source')) { //pseudo action 1241 echo '<option value="edit">'.$lang['btn_source'].'</option>'; 1242 } 1243 }else{ 1244 echo '<option value="show">'.$lang['btn_show'].'</option>'; 1245 } 1246 1247 echo '<option value="revisions">'.$lang['btn_revs'].'</option>'; 1248 echo '<option value="backlink">'.$lang['btn_backlink'].'</option>'; 1249 echo '</optgroup>'; 1250 1251 echo '<optgroup label=" — ">'; 1252 echo '<option value="recent">'.$lang['btn_recent'].'</option>'; 1253 echo '<option value="index">'.$lang['btn_index'].'</option>'; 1254 echo '</optgroup>'; 1255 1256 echo '<optgroup label=" — ">'; 1257 if($conf['useacl'] && $auth){ 1258 if($_SERVER['REMOTE_USER']){ 1259 echo '<option value="logout">'.$lang['btn_logout'].'</option>'; 1260 }else{ 1261 echo '<option value="login">'.$lang['btn_login'].'</option>'; 1262 } 1263 } 1264 1265 if($conf['useacl'] && $auth && $_SERVER['REMOTE_USER'] && 1266 $auth->canDo('Profile') && ($ACT!='profile')){ 1267 echo '<option value="profile">'.$lang['btn_profile'].'</option>'; 1268 } 1269 1270 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers'] == 1){ 1271 if($_SERVER['REMOTE_USER']){ 1272 if($INFO['subscribed']) { 1273 echo '<option value="unsubscribe">'.$lang['btn_unsubscribe'].'</option>'; 1274 } else { 1275 echo '<option value="subscribe">'.$lang['btn_subscribe'].'</option>'; 1276 } 1277 } 1278 } 1279 1280 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers'] == 1){ 1281 if($_SERVER['REMOTE_USER']){ 1282 if($INFO['subscribedns']) { 1283 echo '<option value="unsubscribens">'.$lang['btn_unsubscribens'].'</option>'; 1284 } else { 1285 echo '<option value="subscribens">'.$lang['btn_subscribens'].'</option>'; 1286 } 1287 } 1288 } 1289 1290 if($INFO['ismanager']){ 1291 echo '<option value="admin">'.$lang['btn_admin'].'</option>'; 1292 } 1293 echo '</optgroup>'; 1294 1295 echo '</select>'; 1296 echo '<input type="submit" value="'.$button.'" id="action__selectorbtn" />'; 1297 echo '</form>'; 1298} 1299 1300/** 1301 * Print a informational line about the used license 1302 * 1303 * @author Andreas Gohr <andi@splitbrain.org> 1304 * @param string $img - print image? (|button|badge) 1305 * @param bool $return - when true don't print, but return HTML 1306 */ 1307function tpl_license($img='badge',$return=false){ 1308 global $license; 1309 global $conf; 1310 global $lang; 1311 if(!$conf['license']) return ''; 1312 if(!is_array($license[$conf['license']])) return ''; 1313 $lic = $license[$conf['license']]; 1314 1315 $out = '<p class="license">'; 1316 if($img){ 1317 $src = license_img($img); 1318 if($src){ 1319 $out .= '<a href="'.$lic['url'].'" rel="license"'; 1320 if($conf['target']['external']) $out .= ' target="'.$conf['target']['external'].'"'; 1321 $out .= '><img src="'.DOKU_BASE.$src.'" class="lic'.$img.'" alt="'.$lic['name'].'" align="left" /></a> '; 1322 } 1323 } 1324 $out .= $lang['license']; 1325 $out .= '<a href="'.$lic['url'].'" rel="license" class="urlextern"'; 1326 if($conf['target']['external']) $out .= ' target="'.$conf['target']['external'].'"'; 1327 $out .= '>'.$lic['name'].'</a>'; 1328 $out .= '</p>'; 1329 1330 if($return) return $out; 1331 echo $out; 1332} 1333 1334//Setup VIM: ex: et ts=4 enc=utf-8 : 1335 1336