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