| [ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
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 */ 18 function 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 */ 39 function 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 52 function 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 */ 149 function tpl_toc($return=false){ 150 global $TOC; 151 global $ACT; 152 global $ID; 153 global $REV; 154 global $INFO; 155 $toc = array(); 156 157 if(is_array($TOC)){ 158 // if a TOC was prepared in global scope, always use it 159 $toc = $TOC; 160 }elseif(($ACT == 'show' || substr($ACT,0,6) == 'export') && !$REV && $INFO['exists']){ 161 // get TOC from metadata, render if neccessary 162 $meta = p_get_metadata($ID, false, true); 163 if(isset($meta['internal']['toc'])){ 164 $tocok = $meta['internal']['toc']; 165 }else{ 166 $tocok = true; 167 } 168 $toc = $meta['description']['tableofcontents']; 169 if(!$tocok || !is_array($toc) || count($toc) < 3){ 170 $toc = array(); 171 } 172 }elseif($ACT == 'admin'){ 173 // try to load admin plugin TOC FIXME: duplicates code from tpl_admin 174 $plugin = null; 175 if (!empty($_REQUEST['page'])) { 176 $pluginlist = plugin_list('admin'); 177 if (in_array($_REQUEST['page'], $pluginlist)) { 178 // attempt to load the plugin 179 $plugin =& plugin_load('admin',$_REQUEST['page']); 180 } 181 } 182 if ( ($plugin !== null) && 183 (!$plugin->forAdminOnly() || $INFO['isadmin']) ){ 184 $toc = $plugin->getTOC(); 185 $TOC = $toc; // avoid later rebuild 186 } 187 } 188 189 trigger_event('TPL_TOC_RENDER', $toc, NULL, false); 190 $html = html_TOC($toc); 191 if($return) return $html; 192 echo $html; 193 } 194 195 /** 196 * Handle the admin page contents 197 * 198 * @author Andreas Gohr <andi@splitbrain.org> 199 */ 200 function tpl_admin(){ 201 global $INFO; 202 global $TOC; 203 204 $plugin = null; 205 if (!empty($_REQUEST['page'])) { 206 $pluginlist = plugin_list('admin'); 207 208 if (in_array($_REQUEST['page'], $pluginlist)) { 209 210 // attempt to load the plugin 211 $plugin =& plugin_load('admin',$_REQUEST['page']); 212 } 213 } 214 215 if ($plugin !== null){ 216 if($plugin->forAdminOnly() && !$INFO['isadmin']){ 217 msg('For admins only',-1); 218 html_admin(); 219 }else{ 220 if(!is_array($TOC)) $TOC = $plugin->getTOC(); //if TOC wasn't requested yet 221 if($INFO['prependTOC']) tpl_toc(); 222 $plugin->html(); 223 } 224 }else{ 225 html_admin(); 226 } 227 return true; 228 } 229 230 /** 231 * Print the correct HTML meta headers 232 * 233 * This has to go into the head section of your template. 234 * 235 * @triggers TPL_METAHEADER_OUTPUT 236 * @param boolean $alt Should feeds and alternative format links be added? 237 * @author Andreas Gohr <andi@splitbrain.org> 238 */ 239 function tpl_metaheaders($alt=true){ 240 global $ID; 241 global $REV; 242 global $INFO; 243 global $ACT; 244 global $QUERY; 245 global $lang; 246 global $conf; 247 $it=2; 248 249 // prepare the head array 250 $head = array(); 251 252 253 // the usual stuff 254 $head['meta'][] = array( 'name'=>'generator', 'content'=>'DokuWiki '.getVersion() ); 255 $head['link'][] = array( 'rel'=>'search', 'type'=>'application/opensearchdescription+xml', 256 'href'=>DOKU_BASE.'lib/exe/opensearch.php', 'title'=>$conf['title'] ); 257 $head['link'][] = array( 'rel'=>'start', 'href'=>DOKU_BASE ); 258 if(actionOK('index')){ 259 $head['link'][] = array( 'rel'=>'contents', 'href'=> wl($ID,'do=index',false,'&'), 260 'title'=>$lang['btn_index'] ); 261 } 262 263 if($alt){ 264 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml', 265 'title'=>'Recent Changes', 'href'=>DOKU_BASE.'feed.php'); 266 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml', 267 'title'=>'Current Namespace', 268 'href'=>DOKU_BASE.'feed.php?mode=list&ns='.$INFO['namespace']); 269 if(($ACT == 'show' || $ACT == 'search') && $INFO['writable']){ 270 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/wiki', 271 'title'=>$lang['btn_edit'], 272 'href'=> wl($ID,'do=edit',false,'&')); 273 } 274 275 if($ACT == 'search'){ 276 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'application/rss+xml', 277 'title'=>'Search Result', 278 'href'=>DOKU_BASE.'feed.php?mode=search&q='.$QUERY); 279 } 280 281 if(actionOK('export_xhtml')){ 282 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/html', 'title'=>'Plain HTML', 283 'href'=>exportlink($ID, 'xhtml', '', false, '&')); 284 } 285 286 if(actionOK('export_raw')){ 287 $head['link'][] = array( 'rel'=>'alternate', 'type'=>'text/plain', 'title'=>'Wiki Markup', 288 'href'=>exportlink($ID, 'raw', '', false, '&')); 289 } 290 } 291 292 // setup robot tags apropriate for different modes 293 if( ($ACT=='show' || $ACT=='export_xhtml') && !$REV){ 294 if($INFO['exists']){ 295 //delay indexing: 296 if((time() - $INFO['lastmod']) >= $conf['indexdelay']){ 297 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow'); 298 }else{ 299 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow'); 300 } 301 }else{ 302 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,follow'); 303 } 304 }elseif(defined('DOKU_MEDIADETAIL')){ 305 $head['meta'][] = array( 'name'=>'robots', 'content'=>'index,follow'); 306 }else{ 307 $head['meta'][] = array( 'name'=>'robots', 'content'=>'noindex,nofollow'); 308 } 309 310 // set metadata 311 if($ACT == 'show' || $ACT=='export_xhtml'){ 312 // date of modification 313 if($REV){ 314 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$REV)); 315 }else{ 316 $head['meta'][] = array( 'name'=>'date', 'content'=>date('Y-m-d\TH:i:sO',$INFO['lastmod'])); 317 } 318 319 // keywords (explicit or implicit) 320 if(!empty($INFO['meta']['subject'])){ 321 $head['meta'][] = array( 'name'=>'keywords', 'content'=>join(',',$INFO['meta']['subject'])); 322 }else{ 323 $head['meta'][] = array( 'name'=>'keywords', 'content'=>str_replace(':',',',$ID)); 324 } 325 } 326 327 // load stylesheets 328 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'all', 'type'=>'text/css', 329 'href'=>DOKU_BASE.'lib/exe/css.php?s=all&t='.$conf['template']); 330 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'screen', 'type'=>'text/css', 331 'href'=>DOKU_BASE.'lib/exe/css.php?t='.$conf['template']); 332 $head['link'][] = array('rel'=>'stylesheet', 'media'=>'print', 'type'=>'text/css', 333 'href'=>DOKU_BASE.'lib/exe/css.php?s=print&t='.$conf['template']); 334 335 // load javascript 336 $js_edit = ($ACT=='edit' || $ACT=='preview' || $ACT=='recover' || $ACT=='wordblock' ) ? 1 : 0; 337 $js_write = ($INFO['writable']) ? 1 : 0; 338 if(defined('DOKU_MEDIAMANAGER')){ 339 $js_edit = 1; 340 $js_write = 0; 341 } 342 if(($js_edit && $js_write) || defined('DOKU_MEDIAMANAGER')){ 343 $script = "NS='".$INFO['namespace']."';"; 344 if($conf['useacl'] && $_SERVER['REMOTE_USER']){ 345 require_once (DOKU_INC.'inc/toolbar.php'); 346 $script .= "SIG='".toolbar_signature()."';"; 347 } 348 $head['script'][] = array( 'type'=>'text/javascript', 'charset'=>'utf-8', 349 '_data'=> $script); 350 } 351 $head['script'][] = array( 'type'=>'text/javascript', 'charset'=>'utf-8', '_data'=>'', 352 'src'=>DOKU_BASE.'lib/exe/js.php?edit='.$js_edit.'&write='.$js_write); 353 354 // trigger event here 355 trigger_event('TPL_METAHEADER_OUTPUT',$head,'_tpl_metaheaders_action',true); 356 return true; 357 } 358 359 /** 360 * prints the array build by tpl_metaheaders 361 * 362 * $data is an array of different header tags. Each tag can have multiple 363 * instances. Attributes are given as key value pairs. Values will be HTML 364 * encoded automatically so they should be provided as is in the $data array. 365 * 366 * For tags having a body attribute specify the the body data in the special 367 * attribute '_data'. This field will NOT BE ESCAPED automatically. 368 * 369 * @author Andreas Gohr <andi@splitbrain.org> 370 */ 371 function _tpl_metaheaders_action($data){ 372 foreach($data as $tag => $inst){ 373 foreach($inst as $attr){ 374 echo '<',$tag,' ',buildAttributes($attr); 375 if(isset($attr['_data'])){ 376 if($tag == 'script' && $attr['_data']) 377 $attr['_data'] = "<!--//--><![CDATA[//><!--\n". 378 $attr['_data']. 379 "\n//--><!]]>"; 380 381 echo '>',$attr['_data'],'</',$tag,'>'; 382 }else{ 383 echo '/>'; 384 } 385 echo "\n"; 386 } 387 } 388 } 389 390 /** 391 * Print a link 392 * 393 * Just builds a link. 394 * 395 * @author Andreas Gohr <andi@splitbrain.org> 396 */ 397 function tpl_link($url,$name,$more=''){ 398 print '<a href="'.$url.'" '; 399 if ($more) print ' '.$more; 400 print ">$name</a>"; 401 return true; 402 } 403 404 /** 405 * Prints a link to a WikiPage 406 * 407 * Wrapper around html_wikilink 408 * 409 * @author Andreas Gohr <andi@splitbrain.org> 410 */ 411 function tpl_pagelink($id,$name=NULL){ 412 print html_wikilink($id,$name); 413 return true; 414 } 415 416 /** 417 * get the parent page 418 * 419 * Tries to find out which page is parent. 420 * returns false if none is available 421 * 422 * @author Andreas Gohr <andi@splitbrain.org> 423 */ 424 function tpl_getparent($id){ 425 global $conf; 426 $parent = getNS($id).':'; 427 resolve_pageid('',$parent,$exists); 428 if($parent == $id) { 429 $pos = strrpos (getNS($id),':'); 430 $parent = substr($parent,0,$pos).':'; 431 resolve_pageid('',$parent,$exists); 432 if($parent == $id) return false; 433 } 434 return $parent; 435 } 436 437 /** 438 * Print one of the buttons 439 * 440 * Available Buttons are 441 * 442 * edit - edit/create/show/draft button 443 * history - old revisions 444 * recent - recent changes 445 * login - login/logout button - if ACL enabled 446 * profile - user profile button (if logged in) 447 * index - The index 448 * admin - admin page - if enough rights 449 * top - a back to top button 450 * back - a back to parent button - if available 451 * backlink - links to the list of backlinks 452 * subscription- subscribe/unsubscribe button 453 * 454 * @author Andreas Gohr <andi@splitbrain.org> 455 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 456 */ 457 function tpl_button($type){ 458 global $ACT; 459 global $ID; 460 global $REV; 461 global $NS; 462 global $INFO; 463 global $conf; 464 global $auth; 465 466 // check disabled actions and fix the badly named ones 467 $ctype = $type; 468 if($type == 'history') $ctype='revisions'; 469 if(!actionOK($ctype)) return false; 470 471 switch($type){ 472 case 'edit': 473 #most complicated type - we need to decide on current action 474 if($ACT == 'show' || $ACT == 'search'){ 475 if($INFO['writable']){ 476 if(!empty($INFO['draft'])){ 477 echo html_btn('draft',$ID,'e',array('do' => 'draft'),'post'); 478 }else{ 479 if($INFO['exists']){ 480 echo html_btn('edit',$ID,'e',array('do' => 'edit','rev' => $REV),'post'); 481 }else{ 482 echo html_btn('create',$ID,'e',array('do' => 'edit','rev' => $REV),'post'); 483 } 484 } 485 }else{ 486 if(!actionOK('source')) return false; //pseudo action 487 echo html_btn('source',$ID,'v',array('do' => 'edit','rev' => $REV),'post'); 488 } 489 }else{ 490 echo html_btn('show',$ID,'v',array('do' => 'show')); 491 } 492 return true; 493 case 'history': 494 if(!actionOK('revisions')) 495 return false; 496 print html_btn('revs',$ID,'o',array('do' => 'revisions')); 497 return true; 498 case 'recent': 499 if(!actionOK('recent')) 500 return false; 501 print html_btn('recent',$ID,'r',array('do' => 'recent')); 502 return true; 503 case 'index': 504 if(!actionOK('index')) 505 return false; 506 print html_btn('index',$ID,'x',array('do' => 'index')); 507 return true; 508 case 'back': 509 if ($parent = tpl_getparent($ID)) { 510 print html_btn('back',$parent,'b',array('do' => 'show')); 511 return true; 512 } 513 return false; 514 case 'top': 515 print html_topbtn(); 516 return true; 517 case 'login': 518 if($conf['useacl'] && $auth){ 519 if($_SERVER['REMOTE_USER']){ 520 print html_btn('logout',$ID,'',array('do' => 'logout', 'sectok' => getSecurityToken())); 521 }else{ 522 print html_btn('login',$ID,'',array('do' => 'login', 'sectok' => getSecurityToken())); 523 } 524 return true; 525 } 526 return false; 527 case 'admin': 528 if($INFO['ismanager']){ 529 print html_btn('admin',$ID,'',array('do' => 'admin')); 530 return true; 531 } 532 return false; 533 case 'subscribe': 534 case 'subscription': 535 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers'] == 1){ 536 if($_SERVER['REMOTE_USER']){ 537 if($INFO['subscribed']){ 538 if(!actionOK('unsubscribe')) 539 return false; 540 print html_btn('unsubscribe',$ID,'',array('do' => 'unsubscribe',)); 541 } else { 542 if(!actionOK('subscribe')) 543 return false; 544 print html_btn('subscribe',$ID,'',array('do' => 'subscribe',)); 545 } 546 if($type == 'subscribe') return true; 547 } 548 } 549 if($type == 'subscribe') return false; 550 // fall through for backward compatibility 551 case 'subscribens': 552 if($conf['useacl'] && $auth && $ACT == 'show' && $conf['subscribers'] == 1){ 553 if($_SERVER['REMOTE_USER']){ 554 if($INFO['subscribedns']){ 555 if(!actionOK('unsubscribens')) 556 return false; 557 print html_btn('unsubscribens',$ID,'',array('do' => 'unsubscribens',)); 558 } else { 559 if(!actionOK('subscribens')) 560 return false; 561 print html_btn('subscribens',$ID,'',array('do' => 'subscribens',)); 562 } 563 return true; 564 } 565 } 566 return false; 567 case 'backlink': 568 if(!actionOK('backlink')) 569 return false; 570 print html_btn('backlink',$ID,'',array('do' => 'backlink')); 571 return true; 572 case 'profile': 573 if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $auth && 574 $auth->canDo('Profile') && ($ACT!='profile')){ 575 print html_btn('profile',$ID,'',array('do' => 'profile')); 576 return true; 577 } 578 return false; 579 default: 580 print '[unknown button type]'; 581 return true; 582 } 583 } 584 585 /** 586 * Like the action buttons but links 587 * 588 * Available links are 589 * 590 * edit - edit/create/show link 591 * history - old revisions 592 * recent - recent changes 593 * login - login/logout link - if ACL enabled 594 * profile - user profile link (if logged in) 595 * index - The index 596 * admin - admin page - if enough rights 597 * top - a back to top link 598 * back - a back to parent link - if available 599 * backlink - links to the list of backlinks 600 * subscribe/subscription - subscribe/unsubscribe link 601 * 602 * @author Andreas Gohr <andi@splitbrain.org> 603 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 604 * @see tpl_button 605 */ 606 function tpl_actionlink($type,$pre='',$suf='',$inner=''){ 607 global $ID; 608 global $INFO; 609 global $REV; 610 global $ACT; 611 global $conf; 612 global $lang; 613 global $auth; 614 615 // check disabled actions and fix the badly named ones 616 $ctype = $type; 617 if($type == 'history') $ctype='revisions'; 618 if(!actionOK($ctype)) return false; 619 620 switch($type){ 621 case 'edit': 622 #most complicated type - we need to decide on current action 623 if($ACT == 'show' || $ACT == 'search'){ 624 if($INFO['writable']){ 625 if(!empty($INFO['draft'])) { 626 tpl_link(wl($ID,'do=draft'), 627 $pre.(($inner)?$inner:$lang['btn_draft']).$suf, 628 'class="action edit" accesskey="e" rel="nofollow"'); 629 } else { 630 if($INFO['exis