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