1<?php 2/** 3 * HTML output 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',realpath(dirname(__FILE__).'/../').'/'); 10 require_once(DOKU_INC.'inc/format.php'); 11 12/** 13 * Convenience function to quickly build a wikilink 14 * 15 * @author Andreas Gohr <andi@splitbrain.org> 16 */ 17function html_wikilink($url,$name='',$search=''){ 18 global $conf; 19 $link = array(); 20 $link['url'] = $url; 21 $link['name'] = $name; 22 $link = format_link_wiki($link); 23 24 if($search){ 25 ($conf['userewrite']) ? $link['url'].='?s=' : $link['url'].='&s='; 26 $link['url'] .= urlencode($search); 27 } 28 29 return format_link_build($link); 30} 31 32/** 33 * Helps building long attribute lists 34 * 35 * @author Andreas Gohr <andi@splitbrain.org> 36 */ 37function html_attbuild($attributes){ 38 $ret = ''; 39 foreach ( $attributes as $key => $value ) { 40 $ret .= $key.'="'.formtext($value).'" '; 41 } 42 return trim($ret); 43} 44 45/** 46 * The loginform 47 * 48 * @author Andreas Gohr <andi@splitbrain.org> 49 */ 50function html_login(){ 51 global $lang; 52 global $conf; 53 global $ID; 54 55 print parsedLocale('login'); 56 ?> 57 <div align="center"> 58 <form action="<?=script()?>" accept-charset="<?=$lang['encoding']?>" method="post"> 59 <fieldset> 60 <legend><?=$lang['btn_login']?></legend> 61 <input type="hidden" name="id" value="<?=$ID?>" /> 62 <input type="hidden" name="do" value="login" /> 63 <label> 64 <span><?=$lang['user']?></span> 65 <input type="text" name="u" value="<?=formText($_REQUEST['u'])?>" class="edit" /> 66 </label><br /> 67 <label> 68 <span><?=$lang['pass']?></span> 69 <input type="password" name="p" class="edit" /> 70 </label><br /> 71 <input type="submit" value="<?=$lang['btn_login']?>" class="button" /> 72 <label for="remember" class="simple"> 73 <input type="checkbox" name="r" id="remember" value="1" /> 74 <span><?=$lang['remember']?></span> 75 </label> 76 </fieldset> 77 </form> 78 <? 79 if($conf['openregister']){ 80 print '<p>'; 81 print $lang['reghere']; 82 print ': <a href="'.wl($ID,'do=register').'" class="wikilink1">'.$lang['register'].'</a>'; 83 print '</p>'; 84 } 85 ?> 86 </div> 87 <? 88 if(@file_exists('includes/login.txt')){ 89 print io_cacheParse('includes/login.txt'); 90 } 91} 92 93/** 94 * shows the edit/source/show button dependent on current mode 95 * 96 * @author Andreas Gohr <andi@splitbrain.org> 97 */ 98function html_editbutton(){ 99 global $ID; 100 global $REV; 101 global $ACT; 102 global $INFO; 103 104 if($ACT == 'show' || $ACT == 'search'){ 105 if($INFO['writable']){ 106 if($INFO['exists']){ 107 $r = html_btn('edit',$ID,'e',array('do' => 'edit','rev' => $REV),'post'); 108 }else{ 109 $r = html_btn('create',$ID,'e',array('do' => 'edit','rev' => $REV),'post'); 110 } 111 }else{ 112 $r = html_btn('source',$ID,'v',array('do' => 'edit','rev' => $REV),'post'); 113 } 114 }else{ 115 $r = html_btn('show',$ID,'v',array('do' => 'show')); 116 } 117 return $r; 118} 119 120/** 121 * prints a section editing button 122 * 123 * @author Andreas Gohr <andi@splitbrain.org> 124 */ 125function html_secedit_button($section,$p){ 126 global $ID; 127 global $lang; 128 $secedit = ''; 129 if($p) $secedit .= "</p>\n"; 130 $secedit .= '<div class="secedit">'; 131 $secedit .= html_btn('secedit',$ID,'', 132 array('do' => 'edit', 133 'lines' => "$section"), 134 'post'); 135 $secedit .= '</div>'; 136 if($p) $secedit .= "\n<p>"; 137 return $secedit; 138} 139 140/** 141 * inserts section edit buttons if wanted or removes the markers 142 * 143 * @author Andreas Gohr <andi@splitbrain.org> 144 */ 145function html_secedit($text,$show=true){ 146 global $INFO; 147 if($INFO['writable'] && $show){ 148 $text = preg_replace('#<!-- SECTION \[(\d+-\d+)\] -->#e', 149 "html_secedit_button('\\1',true)", 150 $text); 151 $text = preg_replace('#<!-- SECTION \[(\d+-)\] -->#e', 152 "html_secedit_button('\\1',false)", 153 $text); 154 }else{ 155 $text = preg_replace('#<!-- SECTION \[(\d*-\d*)\] -->#e','',$text); 156 } 157 return $text; 158} 159 160/** 161 * displays the breadcrumbs trace 162 * 163 * @deprecated 164 * @author Andreas Gohr <andi@splitbrain.org> 165 */ 166function html_breadcrumbs(){ 167 global $lang; 168 global $conf; 169 170 //check if enabled 171 if(!$conf['breadcrumbs']) return; 172 173 $crumbs = breadcrumbs(); //setup crumb trace 174 print '<div class="breadcrumbs">'; 175 print $lang['breadcrumb'].':'; 176 foreach ($crumbs as $crumb){ 177 print ' » '; 178 print '<a href="'.wl($crumb).'" class="breadcrumbs" onclick="return svchk()" onkeypress="return svchk()" title="'.$crumb.'">'.noNS($crumb).'</a>'; 179 } 180 print '</div>'; 181} 182 183/** 184 * display the HTML head and metadata 185 * 186 * @deprecated -> tpl_metaheaders() 187 * @author Andreas Gohr <andi@splitbrain.org> 188 */ 189function html_head(){ 190 global $ID; 191 global $ACT; 192 global $INFO; 193 global $REV; 194 global $conf; 195 global $lang; 196 197 //print '<'.'?xml version="1.0"?'.">\n"; 198 print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'; 199 print ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'; 200 print "\n"; 201?> 202 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?=$conf['lang']?>" lang="<?=$conf['lang']?>" dir="ltr"> 203 <head> 204 <title><?=$ID?> [<?=$conf['title']?>]</title> 205 <meta http-equiv="Content-Type" content="text/html; charset=<?=$lang['encoding']?>" /> 206 <meta name="generator" content="DokuWiki <?=getVersion()?>" /> 207 <link rel="stylesheet" media="screen" type="text/css" href="<?=DOKU_BASE?>style.css" /> 208 <link rel="stylesheet" media="print" type="text/css" href="<?=DOKU_BASE?>print.css" /> 209 <link rel="shortcut icon" href="<?=DOKU_BASE?>images/favicon.ico" /> 210 <link rel="start" href="<?=wl()?>" /> 211 <link rel="contents" href="<?=wl($ID,'do=index')?>" title="<?=$lang['index']?>" /> 212 <link rel="alternate" type="application/rss+xml" title="Recent Changes" href="<?=DOKU_BASE?>feed.php" /> 213 <link rel="alternate" type="application/rss+xml" title="Current Namespace" href="<?=DOKU_BASE?>feed.php?mode=list&ns=<?=$INFO['namespace']?>" /> 214 <link rel="alternate" type="text/html" title="Plain HTML" href="<?=wl($ID,'do=export_html')?>" /> 215 <link rel="alternate" type="text/plain" title="Wiki Markup" href="<?=wl($ID, 'do=export_raw')?>" /> 216<? 217 if( ($ACT=='show' || $ACT=='export_html') && !$REV){ 218 if($INFO['exists']){ 219 print ' <meta name="robots" content="index,follow" />'."\n"; 220 print ' <meta name="date" content="'.date('Y-m-d\TH:i:sO',$INFO['lastmod']).'" />'."\n"; 221 }else{ 222 print ' <meta name="robots" content="noindex,follow" />'."\n"; 223 } 224 }else{ 225 print ' <meta name="robots" content="noindex,nofollow" />'."\n"; 226 } 227?> 228 229 <script language="JavaScript" type="text/javascript"> 230 var alertText = '<?=$lang['qb_alert']?>'; 231 var notSavedYet = '<?=$lang['notsavedyet']?>'; 232 var DOKU_BASE = '<?=DOKU_BASE?>'; 233 </script> 234 <script language="JavaScript" type="text/javascript" src="<?=DOKU_BASE?>script.js"></script> 235 236 <!--[if gte IE 5]> 237 <style type="text/css"> 238 /* that IE 5+ conditional comment makes this only visible in IE 5+ */ 239 img { behavior: url("<?=DOKU_BASE?>pngbehavior.htc"); } /* IE bugfix for transparent PNGs */ 240 </style> 241 <![endif]--> 242 243 <?@include("includes/meta.html")?> 244 </head> 245<? 246} 247 248/** 249 * Just the back to top button (in it's own form) 250 * 251 * @author Andreas Gohr <andi@splitbrain.org> 252 */ 253function html_topbtn(){ 254 global $lang; 255 256 $ret = ''; 257 $ret .= '<form class="button" method="get" action="#top" onsubmit="return svchk()">'; 258 $ret .= '<input type="submit" value="'.htmlspecialchars($lang['btn_top']).'" class="button" '; 259 $ret .= '</form>'; 260 return $ret; 261} 262 263/** 264 * Displays a button (using it's own form) 265 * 266 * @author Andreas Gohr <andi@splitbrain.org> 267 */ 268function html_btn($name,$id,$akey,$params,$method='get'){ 269 global $conf; 270 global $lang; 271 272 $label = $lang['btn_'.$name]; 273 274 $ret = ''; 275 276 //filter id (without urlencoding) 277 $id = idfilter($id,false); 278 279 //make nice URLs even for buttons 280 if(!$conf['userewrite']){ 281 $script = DOKU_BASE.DOKU_SCRIPT; 282 $params['id'] = $id; 283 }else{ 284 $script = DOKU_BASE.$id; 285 } 286 287 $ret .= '<form class="button" method="'.$method.'" action="'.$script.'" onsubmit="return svchk()">'; 288 289 reset($params); 290 while (list($key, $val) = each($params)) { 291 $ret .= '<input type="hidden" name="'.$key.'" '; 292 $ret .= 'value="'.htmlspecialchars($val).'" />'; 293 } 294 295 $ret .= '<input type="submit" value="'.htmlspecialchars($label).'" class="button" '; 296 if($akey){ 297 $ret .= 'title="ALT+'.strtoupper($akey).'" '; 298 $ret .= 'accesskey="'.$akey.'" '; 299 } 300 $ret .= '/>'; 301 $ret .= '</form>'; 302 303 return $ret; 304} 305 306/** 307 * Check for the given permission or prints an error 308 * 309 * @deprecated 310 * @author Andreas Gohr <andi@splitbrain.org> 311 */ 312function html_acl($perm){ 313 global $INFO; 314 if($INFO['perm'] >= $perm) return true; 315 316 print parsedLocale('denied'); 317 return false; 318} 319 320/** 321 * Displays the overall page header and calls html_head() 322 * 323 * @author Andreas Gohr <andi@splitbrain.org> 324 */ 325function html_header(){ 326 global $ID; 327 global $REV; 328 global $lang; 329 global $conf; 330 html_head(); 331?> 332<body> 333 <div class="all"> 334 <? 335 @include("includes/topheader.html"); 336 html_msgarea(); 337 ?> 338 <div class="stylehead"> 339 <div class="header"> 340 <div class="pagename"> 341 [[<a href="<?=wl($ID,'do=backlink')?>" onclick="return svchk()" onkeypress="return svchk()"><?=$ID?></a>]] 342 </div> 343 <div class="logo"> 344 <a href="<?=wl()?>" name="top" accesskey="h" title="[ALT+H]" onclick="return svchk()" onkeypress="return svchk()"><?=$conf['title']?></a> 345 </div> 346 </div> 347 <?@include("includes/header.html")?> 348 349 <div class="bar" id="bar_top"> 350 <div class="bar-left" id="bar_topleft"> 351 <?=html_editbutton()?> 352 <?=html_btn(revs,$ID,'o',array('do' => 'revisions'))?> 353 </div> 354 355 <div class="bar-right" id="bar_topright"> 356 <?=html_btn(recent,'','r',array('do' => 'recent'))?> 357 <form action="<?=wl()?>" accept-charset="<?=$lang['encoding']?>"> 358 <input type="hidden" name="do" value="search" /> 359 <input type="text" accesskey="f" name="id" class="edit" /> 360 <input type="submit" value="<?=$lang['btn_search']?>" class="button" /> 361 </form> 362 </div> 363 </div> 364 365 <? 366 flush(); 367 html_breadcrumbs(); 368 @include("includes/pageheader.html"); 369 ?> 370 </div> 371 <div class="page"> 372 <!-- wikipage start --> 373<? 374} 375 376/** 377 * display document and user info 378 * 379 * Displays some Metadata like who's logged in and the last modified 380 * date - do not confuse this with the HTML meta header. 381 * 382 * @author Andreas Gohr <andi@splitbrain.org> 383 */ 384function html_metainfo(){ 385 global $conf; 386 global $lang; 387 global $INFO; 388 global $REV; 389 390 $fn = $INFO['filepath']; 391 if(!$conf['fullpath']){ 392 if($REV){ 393 $fn = str_replace(realpath($conf['olddir']).DIRECTORY_SEPARATOR,'',$fn); 394 }else{ 395 $fn = str_replace(realpath($conf['datadir']).DIRECTORY_SEPARATOR,'',$fn); 396 } 397 } 398 $date = date($conf['dformat'],$INFO['lastmod']); 399 400 print '<div class="meta">'; 401 if($_SERVER['REMOTE_USER']){ 402 print '<div class="user">'; 403 print $lang['loggedinas'].': '.$_SERVER['REMOTE_USER']; 404 print '</div>'; 405 } 406 print ' '; 407 if($INFO['exists']){ 408 print $fn; 409 print ' · '; 410 print $lang['lastmod']; 411 print ': '; 412 print $date; 413 if($INFO['editor']){ 414 print ' '.$lang['by'].' '; 415 print $INFO['editor']; 416 } 417 if($INFO['locked']){ 418 print ' · '; 419 print $lang['lockedby']; 420 print ': '; 421 print $INFO['locked']; 422 } 423 } 424 print '</div>'; 425} 426 427/** 428 * Diplay the overall footer 429 * 430 * @author Andreas Gohr <andi@splitbrain.org> 431 */ 432function html_footer(){ 433 global $ID; 434 global $REV; 435 global $INFO; 436 global $lang; 437 global $conf; 438?> 439 <!-- wikipage stop --> 440 </div> 441 <div class="clearer"> </div> 442 <div class="stylefoot"> 443 <? 444 flush(); 445 @include("includes/pagefooter.html"); 446 html_metainfo(); 447 ?> 448 <div class="bar" id="bar_bottom"> 449 <div class="bar-left" id="bar_bottomleft"> 450 <?=html_editbutton()?> 451 <?=html_btn(revs,$ID,'o',array('do' => 'revisions'))?> 452 </div> 453 454 <div class="bar-right" id="bar_bottomright"> 455 <? 456 if($conf['useacl']){ 457 if($_SERVER['REMOTE_USER']){ 458 print html_btn('logout',$ID,'',array('do' => 'logout',)); 459 }else{ 460 print html_btn('login',$ID,'',array('do' => 'login')); 461 } 462 #//acl-admin button 463 #if($INFO['perm'] == AUTH_GRANT){ 464 # print html_btn('acl_admin',$ID,'',array('do' => 'acl_admin')); 465 #} 466 } 467 ?> 468 <?=html_btn(index,$ID,'x',array('do' => 'index'))?> 469 <a href="#top"><input type="button" class="button" value="<?=$lang['btn_top']?>" /></a> 470 </div> 471 </div> 472 </div> 473 <?@include("includes/footer.html")?> 474 </div> 475 </body> 476 </html> 477<? 478} 479 480/** 481 * Print the table of contents 482 * 483 * @author Andreas Gohr <andi@splitbrain.org> 484 */ 485function html_toc($toc){ 486 global $lang; 487 $ret = ''; 488 $ret .= '<div class="toc">'; 489 $ret .= '<div class="tocheader">'; 490 $ret .= $lang['toc']; 491 $ret .= ' <script type="text/javascript">'; 492 $ret .= 'showTocToggle("+","-")'; 493 $ret .= '</script>'; 494 $ret .= '</div>'; 495 $ret .= '<div id="tocinside">'; 496 $ret .= html_buildlist($toc,'toc','html_list_toc'); 497 $ret .= '</div>'; 498 $ret .= '</div>'; 499 return $ret; 500} 501 502/** 503 * TOC item formatter 504 * 505 * User function for html_buildlist() 506 * 507 * @author Andreas Gohr <andi@splitbrain.org> 508 */ 509function html_list_toc($item){ 510 $ret = ''; 511 $ret .= '<a href="#'.$item['id'].'" class="toc">'; 512 $ret .= $item['name']; 513 $ret .= '</a>'; 514 return $ret; 515} 516 517/** 518 * show a wiki page 519 * 520 * @author Andreas Gohr <andi@splitbrain.org> 521 */ 522function html_show($text=''){ 523 global $ID; 524 global $REV; 525 global $HIGH; 526 //disable section editing for old revisions or in preview 527 if($text || $REV){ 528 global $parser; 529 $parser['secedit'] = false; 530 } 531 532 if ($text){ 533 //PreviewHeader 534 print parsedLocale('preview'); 535 print '<div class="preview">'; 536 print html_secedit(parse($text),false); 537 print '</div>'; 538 }else{ 539 if ($REV) print parsedLocale('showrev'); 540 $html = parsedWiki($ID,$REV,true); 541 $html = html_secedit($html); 542 print html_hilight($html,$HIGH); 543 } 544} 545 546/** 547 * Highlights searchqueries in HTML code 548 * 549 * @author Andreas Gohr <andi@splitbrain.org> 550 */ 551function html_hilight($html,$query){ 552 $queries = preg_split ("/\s/",$query,-1,PREG_SPLIT_NO_EMPTY); 553 foreach ($queries as $q){ 554 $q = preg_quote($q,'/'); 555 $html = preg_replace("/((<[^>]*)|$q)/ie", '"\2"=="\1"? "\1":"<span class=\"search_hit\">\1</span>"', $html); 556 } 557 return $html; 558} 559 560/** 561 * Run a search and display the result 562 * 563 * @author Andreas Gohr <andi@splitbrain.org> 564 */ 565function html_search(){ 566 require_once(DOKU_INC.'inc/search.php'); 567 global $conf; 568 global $QUERY; 569 global $ID; 570 global $lang; 571 572 print parsedLocale('searchpage'); 573 flush(); 574 575 //show progressbar 576 print '<div align="center">'; 577 print '<script language="JavaScript" type="text/javascript">'; 578 print 'showLoadBar();'; 579 print '</script>'; 580 print '<br /></div>'; 581 582 //do quick pagesearch 583 $data = array(); 584 search($data,$conf['datadir'],'search_pagename',array(query => cleanID($QUERY))); 585 if(count($data)){ 586 sort($data); 587 print '<div class="search_quickresult">'; 588 print '<b>'.$lang[quickhits].':</b><br />'; 589 foreach($data as $row){ 590 print '<div class="search_quickhits">'; 591 print html_wikilink(':'.$row['id'],$row['id']); 592 print '</div> '; 593 } 594 //clear float (see http://www.complexspiral.com/publications/containing-floats/) 595 print '<div class="clearer"> </div>'; 596 print '</div>'; 597 } 598 flush(); 599 600 //do fulltext search 601 $data = array(); 602 search($data,$conf['datadir'],'search_fulltext',array(query => utf8_strtolower($QUERY))); 603 if(count($data)){ 604 usort($data,'sort_search_fulltext'); 605 foreach($data as $row){ 606 print '<div class="search_result">'; 607 print html_wikilink(':'.$row['id'],$row['id'],$QUERY); 608 print ': <span class="search_cnt">'.$row['count'].' '.$lang['hits'].'</span><br />'; 609 print '<div class="search_snippet">'.$row['snippet'].'</div>'; 610 print '</div>'; 611 } 612 }else{ 613 print '<div class="nothing">'.$lang['nothingfound'].'</div>'; 614 } 615 616 //hide progressbar 617 print '<script language="JavaScript" type="text/javascript">'; 618 print 'hideLoadBar();'; 619 print '</script>'; 620} 621 622/** 623 * Display error on locked pages 624 * 625 * @author Andreas Gohr <andi@splitbrain.org> 626 */ 627function html_locked($ip){ 628 global $ID; 629 global $conf; 630 global $lang; 631 632 $locktime = filemtime(wikiFN($ID).'.lock'); 633 $expire = @date($conf['dformat'], $locktime + $conf['locktime'] ); 634 $min = round(($conf['locktime'] - (time() - $locktime) )/60); 635 636 print parsedLocale('locked'); 637 print '<ul>'; 638 print '<li><b>'.$lang['lockedby'].':</b> '.$ip.'</li>'; 639 print '<li><b>'.$lang['lockexpire'].':</b> '.$expire.' ('.$min.' min)</li>'; 640 print '</ul>'; 641} 642 643/** 644 * list old revisions 645 * 646 * @author Andreas Gohr <andi@splitbrain.org> 647 */ 648function html_revisions(){ 649 global $ID; 650 global $INFO; 651 global $conf; 652 global $lang; 653 $revisions = getRevisions($ID); 654 $date = @date($conf['dformat'],$INFO['lastmod']); 655 656 print parsedLocale('revisions'); 657 print '<ul>'; 658 if($INFO['exists']){ 659 print '<li>'; 660 print $date.' <a class="wikilink1" href="'.wl($ID).'">'.$ID.'</a> '; 661 662 print $INFO['sum']; 663 print ' <span class="user">('; 664 print $INFO['ip']; 665 if($INFO['user']) print ' '.$INFO['user']; 666 print ')</span> '; 667 668 print '('.$lang['current'].')'; 669 print '</li>'; 670 } 671 672 foreach($revisions as $rev){ 673 $date = date($conf['dformat'],$rev); 674 $info = getRevisionInfo($ID,$rev); 675 676 print '<li>'; 677 print $date.' <a class="wikilink1" href="'.wl($ID,"rev=$rev").'">'.$ID.'</a> '; 678 print $info['sum']; 679 print ' <span class="user">('; 680 print $info['ip']; 681 if($info['user']) print ' '.$info['user']; 682 print ')</span> '; 683 684 print '<a href="'.wl($ID,"rev=$rev,do=diff").'">'; 685 print '<img src="'.DOKU_BASE.'images/diff.png" border="0" width="15" height="11" title="'.$lang['diff'].'" />'; 686 print '</a>'; 687 print '</li>'; 688 } 689 print '</ul>'; 690} 691 692/** 693 * display recent changes 694 * 695 * @author Andreas Gohr <andi@splitbrain.org> 696 */ 697function html_recent(){ 698 global $conf; 699 $recents = getRecents(0,true); 700 701 print parsedLocale('recent'); 702 print '<ul>'; 703 foreach(array_keys($recents) as $id){ 704 $date = date($conf['dformat'],$recents[$id]['date']); 705 print '<li>'; 706 print $date.' '.html_wikilink($id,$id); 707 print ' '.htmlspecialchars($recents[$id]['sum']); 708 print ' <span class="user">('; 709 print $recents[$id]['ip']; 710 if($recents[$id]['user']) print ' '.$recents[$id]['user']; 711 print ')</span>'; 712 print '</li>'; 713 } 714 print '</ul>'; 715} 716 717/** 718 * Display page index 719 * 720 * @author Andreas Gohr <andi@splitbrain.org> 721 */ 722function html_index($ns){ 723 require_once(DOKU_INC.'inc/search.php'); 724 global $conf; 725 global $ID; 726 $dir = $conf['datadir']; 727 $ns = cleanID($ns); 728 if(empty($ns)){ 729 $ns = dirname(str_replace(':','/',$ID)); 730 if($ns == '.') $ns =''; 731 } 732 $ns = utf8_encodeFN(str_replace(':','/',$ns)); 733 734 print parsedLocale('index'); 735 736 $data = array(); 737 search($data,$conf['datadir'],'search_index',array('ns' => $ns)); 738 print html_buildlist($data,'idx','html_list_index','html_li_index'); 739} 740 741/** 742 * Index item formatter 743 * 744 * User function for html_buildlist() 745 * 746 * @author Andreas Gohr <andi@splitbrain.org> 747 */ 748function html_list_index($item){ 749 $ret = ''; 750 $base = ':'.$item['id']; 751 $base = substr($base,strrpos($base,':')+1); 752 if($item['type']=='d'){ 753 $ret .= '<a href="'.wl($ID,'idx='.$item['id']).'" class="idx_dir">'; 754 $ret .= $base; 755 $ret .= '</a>'; 756 }else{ 757 $ret .= html_wikilink(':'.$item['id']); 758 } 759 return $ret; 760} 761 762/** 763 * Index List item 764 * 765 * This user function is used in html_build_lidt to build the 766 * <li> tags for namespaces when displaying the page index 767 * it gives different classes to opened or closed "folders" 768 * 769 * @author Andreas Gohr <andi@splitbrain.org> 770 */ 771function html_li_index($item){ 772 if($item['type'] == "f"){ 773 return '<li class="level'.$item['level'].'">'; 774 }elseif($item['open']){ 775 return '<li class="open">'; 776 }else{ 777 return '<li class="closed">'; 778 } 779} 780 781/** 782 * Default List item 783 * 784 * @author Andreas Gohr <andi@splitbrain.org> 785 */ 786function html_li_default($item){ 787 return '<li class="level'.$item['level'].'">'; 788} 789 790/** 791 * Build an unordered list 792 * 793 * Build an unordered list from the given $data array 794 * Each item in the array has to have a 'level' property 795 * the item itself gets printed by the given $func user 796 * function. The second and optional function is used to 797 * print the <li> tag. Both user function need to accept 798 * a single item. 799 * 800 * @author Andreas Gohr <andi@splitbrain.org> 801 */ 802function html_buildlist($data,$class,$func,$lifunc='html_li_default'){ 803 $level = 0; 804 $opens = 0; 805 $ret = ''; 806 807 foreach ($data as $item){ 808 809 if( $item['level'] > $level ){ 810 //open new list 811 for($i=0; $i<($item['level'] - $level); $i++){ 812 if ($i) $ret .= "<li class=\"clear\">\n"; 813 $ret .= "\n<ul class=\"$class\">\n"; 814 } 815 }elseif( $item['level'] < $level ){ 816 //close last item 817 $ret .= "</li>\n"; 818 for ($i=0; $i<($level - $item['level']); $i++){ 819 //close higher lists 820 $ret .= "</ul>\n</li>\n"; 821 } 822 }else{ 823 //close last item 824 $ret .= "</li>\n"; 825 } 826 827 //remember current level 828 $level = $item['level']; 829 830 //print item 831 $ret .= $lifunc($item); //user function 832 $ret .= '<span class="li">'; 833 $ret .= $func($item); //user function 834 $ret .= '</span>'; 835 } 836 837 //close remaining items and lists 838 for ($i=0; $i < $level; $i++){ 839 $ret .= "</li></ul>\n"; 840 } 841 842 return $ret; 843} 844 845/** 846 * display backlinks 847 * 848 * @author Andreas Gohr <andi@splitbrain.org> 849 */ 850function html_backlinks(){ 851 require_once(DOKU_INC.'inc/search.php'); 852 global $ID; 853 global $conf; 854 855 if(preg_match('#^(.*):(.*)$#',$ID,$matches)){ 856 $opts['ns'] = $matches[1]; 857 $opts['name'] = $matches[2]; 858 }else{ 859 $opts['ns'] = ''; 860 $opts['name'] = $ID; 861 } 862 863 print parsedLocale('backlinks'); 864 865 $data = array(); 866 search($data,$conf['datadir'],'search_backlinks',$opts); 867 sort($data); 868 869 print '<ul class="idx">'; 870 foreach($data as $row){ 871 print '<li>'; 872 print html_wikilink(':'.$row['id'],$row['id']); 873 print '</li>'; 874 } 875 print '</ul>'; 876} 877 878/** 879 * show diff 880 * 881 * @author Andreas Gohr <andi@splitbrain.org> 882 */ 883function html_diff($text='',$intro=true){ 884 require_once(DOKU_INC.'inc/DifferenceEngine.php'); 885 global $ID; 886 global $REV; 887 global $lang; 888 global $conf; 889 if($text){ 890 $df = new Diff(split("\n",htmlspecialchars(rawWiki($ID,''))), 891 split("\n",htmlspecialchars(cleanText($text)))); 892 $left = '<a class="wikilink1" href="'.wl($ID).'">'. 893 $ID.' '.date($conf['dformat'],@filemtime(wikiFN($ID))).'</a>'. 894 $lang['current']; 895 $right = $lang['yours']; 896 }else{ 897 $df = new Diff(split("\n",htmlspecialchars(rawWiki($ID,$REV))), 898 split("\n",htmlspecialchars(rawWiki($ID,'')))); 899 $left = '<a class="wikilink1" href="'.wl($ID,"rev=$REV").'">'. 900 $ID.' '.date($conf['dformat'],$REV).'</a>'; 901 $right = '<a class="wikilink1" href="'.wl($ID).'">'. 902 $ID.' '.date($conf['dformat'],@filemtime(wikiFN($ID))).'</a> '. 903 $lang['current']; 904 } 905 $tdf = new TableDiffFormatter(); 906 if($intro) print parsedLocale('diff'); 907 ?> 908 <table class="diff" width="100%"> 909 <tr> 910 <td colspan="2" width="50%" class="diff-header"> 911 <?=$left?> 912 </td> 913 <td colspan="2" width="50%" class="diff-header"> 914 <?=$right?> 915 </td> 916 </tr> 917 <?=$tdf->format($df)?> 918 </table> 919 <? 920} 921 922/** 923 * show warning on conflict detection 924 * 925 * @author Andreas Gohr <andi@splitbrain.org> 926 */ 927function html_conflict($text,$summary){ 928 global $ID; 929 global $lang; 930 931 print parsedLocale('conflict'); 932 ?> 933 <form name="editform" method="post" action="<?=script()?>" accept-charset="<?=$lang['encoding']?>"> 934 <input type="hidden" name="id" value="<?=$ID?>" /> 935 <input type="hidden" name="wikitext" value="<?=formText($text)?>" /> 936 <input type="hidden" name="summary" value="<?=formText($summary)?>" /> 937 938 <div align="center"> 939 <input class="button" type="submit" name="do" value="<?=$lang['btn_save']?>" accesskey="s" title="[ALT+S]" /> 940 <input class="button" type="submit" name="do" value="<?=$lang['btn_cancel']?>" /> 941 </div> 942 </form> 943 <br /><br /><br /><br /> 944 <? 945} 946 947/** 948 * Prints the global message array 949 * 950 * @author Andreas Gohr <andi@splitbrain.org> 951 */ 952function html_msgarea(){ 953 global $MSG; 954 955 if(!isset($MSG)) return; 956 957 foreach($MSG as $msg){ 958 print '<div class="'.$msg['lvl'].'">'; 959 print $msg['msg']; 960 print '</div>'; 961 } 962} 963 964/** 965 * Prints the registration form 966 * 967 * @author Andreas Gohr <andi@splitbrain.org> 968 */ 969function html_register(){ 970 global $lang; 971 global $ID; 972 973 print parsedLocale('register'); 974?> 975 <div align="center"> 976 <form name="register" method="post" action="<?=wl($ID)?>" accept-charset="<?=$lang['encoding']?>"> 977 <input type="hidden" name="do" value="register" /> 978 <input type="hidden" name="save" value="1" /> 979 <fieldset> 980 <legend><?=$lang['register']?></legend> 981 <label> 982 <?=$lang['user']?> 983 <input type="text" name="login" class="edit" size="50" value="<?=formText($_POST['login'])?>" /> 984 </label><br /> 985 <label> 986 <?=$lang['fullname']?> 987 <input type="text" name="fullname" class="edit" size="50" value="<?=formText($_POST['fullname'])?>" /> 988 </label><br /> 989 <label> 990 <?=$lang['email']?> 991 <input type="text" name="email" class="edit" size="50" value="<?=formText($_POST['email'])?>" /> 992 </label><br /> 993 <input type="submit" class="button" value="<?=$lang['register']?>" /> 994 </fieldset> 995 </form> 996 </div> 997<? 998} 999 1000/** 1001 * This displays the edit form (lots of logic included) 1002 * 1003 * @author Andreas Gohr <andi@splitbrain.org> 1004 */ 1005function html_edit($text=null,$include='edit'){ //FIXME: include needed? 1006 global $ID; 1007 global $REV; 1008 global $DATE; 1009 global $RANGE; 1010 global $PRE; 1011 global $SUF; 1012 global $INFO; 1013 global $SUM; 1014 global $lang; 1015 global $conf; 1016 1017 //check for create permissions first 1018 if(!$INFO['exists'] && !html_acl(AUTH_CREATE)) return; 1019 1020 //set summary default 1021 if(!$SUM){ 1022 if($REV){ 1023 $SUM = $lang['restored']; 1024 }elseif(!$INFO['exists']){ 1025 $SUM = $lang['created']; 1026 } 1027 } 1028 1029 //no text? Load it! 1030 if(!isset($text)){ 1031 $pr = false; //no preview mode 1032 if($RANGE){ 1033 list($PRE,$text,$SUF) = rawWikiSlices($RANGE,$ID,$REV); 1034 }else{ 1035 $text = rawWiki($ID,$REV); 1036 } 1037 }else{ 1038 $pr = true; //preview mode 1039 } 1040 1041 $wr = $INFO['writable']; 1042 if($wr){ 1043 if ($REV) print parsedLocale('editrev'); 1044 print parsedLocale($include); 1045 }else{ 1046 print parsedLocale('read'); 1047 $ro='readonly="readonly"'; 1048 } 1049 if(!$DATE) $DATE = $INFO['lastmod']; 1050?> 1051 <form name="editform" method="post" action="<?=script()?>" accept-charset="<?=$lang['encoding']?>" onsubmit="return svchk()"> 1052 <input type="hidden" name="id" value="<?=$ID?>" /> 1053 <input type="hidden" name="rev" value="<?=$REV?>" /> 1054 <input type="hidden" name="date" value="<?=$DATE?>" /> 1055 <input type="hidden" name="prefix" value="<?=formText($PRE)?>" /> 1056 <input type="hidden" name="suffix" value="<?=formText($SUF)?>" /> 1057 <table style="width:99%"> 1058 <tr> 1059 <td class="toolbar" colspan="3"> 1060 <?if($wr){?> 1061 <script language="JavaScript" type="text/javascript"> 1062 <?/* sets changed to true when previewed */?> 1063 textChanged = <? ($pr) ? print 'true' : print 'false' ?>; 1064 1065 formatButton('images/bold.png','<?=$lang['qb_bold']?>','**','**','<?=$lang['qb_bold']?>','b'); 1066 formatButton('images/italic.png','<?=$lang['qb_italic']?>',"\/\/","\/\/",'<?=$lang['qb_italic']?>','i'); 1067 formatButton('images/underline.png','<?=$lang['qb_underl']?>','__','__','<?=$lang['qb_underl']?>','u'); 1068 formatButton('images/code.png','<?=$lang['qb_code']?>','\'\'','\'\'','<?=$lang['qb_code']?>','c'); 1069 1070 formatButton('images/fonth1.png','<?=$lang['qb_h1']?>','====== ',' ======\n','<?=$lang['qb_h1']?>','1'); 1071 formatButton('images/fonth2.png','<?=$lang['qb_h2']?>','===== ',' =====\n','<?=$lang['qb_h2']?>','2'); 1072 formatButton('images/fonth3.png','<?=$lang['qb_h3']?>','==== ',' ====\n','<?=$lang['qb_h3']?>','3'); 1073 formatButton('images/fonth4.png','<?=$lang['qb_h4']?>','=== ',' ===\n','<?=$lang['qb_h4']?>','4'); 1074 formatButton('images/fonth5.png','<?=$lang['qb_h5']?>','== ',' ==\n','<?=$lang['qb_h5']?>','5'); 1075 1076 formatButton('images/link.png','<?=$lang['qb_link']?>','[[',']]','<?=$lang['qb_link']?>','l'); 1077 formatButton('images/extlink.png','<?=$lang['qb_extlink']?>','[[',']]','http://www.example.com|<?=$lang['qb_extlink']?>'); 1078 1079 formatButton('images/list.png','<?=$lang['qb_ol']?>',' - ','\n','<?=$lang['qb_ol']?>'); 1080 formatButton('images/list_ul.png','<?=$lang['qb_ul']?>',' * ','\n','<?=$lang['qb_ul']?>'); 1081 1082 insertButton('images/rule.png','<?=$lang['qb_hr']?>','----\n'); 1083 mediaButton('images/image.png','<?=$lang['qb_media']?>','m','<?=$INFO['namespace']?>'); 1084 1085 <? 1086 if($conf['useacl'] && $_SERVER['REMOTE_USER']){ 1087 echo "insertButton('images/sig.png','".$lang['qb_sig']."','".html_signature()."','y');"; 1088 } 1089 ?> 1090 </script> 1091 <?}?> 1092 </td> 1093 </tr> 1094 <tr> 1095 <td colspan="3"> 1096 <textarea name="wikitext" id="wikitext" <?=$ro?> cols="80" rows="10" class="edit" onchange="textChanged = true;" onkeyup="summaryCheck();" tabindex="1"><?="\n".formText($text)?></textarea> 1097 </td> 1098 </tr> 1099 <tr> 1100 <td> 1101 <?if($wr){?> 1102 <input class="button" type="submit" name="do" value="<?=$lang['btn_save']?>" accesskey="s" title="[ALT+S]" onclick="textChanged=false" onkeypress="textChanged=false" tabindex="3" /> 1103 <input class="button" type="submit" name="do" value="<?=$lang['btn_preview']?>" accesskey="p" title="[ALT+P]" onclick="textChanged=false" onkeypress="textChanged=false" tabindex="4" /> 1104 <input class="button" type="submit" name="do" value="<?=$lang['btn_cancel']?>" tabindex="5" /> 1105 <?}?> 1106 </td> 1107 <td> 1108 <?if($wr){?> 1109 <?=$lang['summary']?>: 1110 <input type="text" class="edit" name="summary" id="summary" size="50" onkeyup="summaryCheck();" value="<?=formText($SUM)?>" tabindex="2" /> 1111 <?}?> 1112 </td> 1113 <td align="right"> 1114 <script type="text/javascript"> 1115 showSizeCtl(); 1116 <?if($wr){?> 1117 init_locktimer(<?=$conf['locktime']-60?>,'<?=$lang['willexpire']?>'); 1118 document.editform.wikitext.focus(); 1119 <?}?> 1120 </script> 1121 </td> 1122 </tr> 1123 </table> 1124 </form> 1125<? 1126} 1127 1128/** 1129 * prepares the signature string as configured in the config 1130 * 1131 * @author Andreas Gohr <andi@splitbrain.org> 1132 */ 1133function html_signature(){ 1134 global $conf; 1135 global $INFO; 1136 1137 $sig = $conf['signature']; 1138 $sig = strftime($sig); 1139 $sig = str_replace('@USER@',$_SERVER['REMOTE_USER'],$sig); 1140 $sig = str_replace('@NAME@',$INFO['userinfo']['name'],$sig); 1141 $sig = str_replace('@MAIL@',$INFO['userinfo']['mail'],$sig); 1142 $sig = str_replace('@DATE@',date($conf['dformat']),$sig); 1143 return $sig; 1144} 1145 1146/** 1147 * prints some debug info 1148 * 1149 * @author Andreas Gohr <andi@splitbrain.org> 1150 */ 1151function html_debug(){ 1152 global $conf; 1153 global $lang; 1154 //remove sensitive data 1155 $cnf = $conf; 1156 $cnf['auth']='***'; 1157 $cnf['notify']='***'; 1158 $cnf['ftp']='***'; 1159 1160 print '<html><body>'; 1161 1162 print '<p>When reporting bugs please send all the following '; 1163 print 'output as a mail to andi@splitbrain.org '; 1164 print 'The best way to do this is to save this page in your browser</p>'; 1165 1166 print '<b>$_SERVER:</b><pre>'; 1167 print_r($_SERVER); 1168 print '</pre>'; 1169 1170 print '<b>$conf:</b><pre>'; 1171 print_r($cnf); 1172 print '</pre>'; 1173 1174 print '<b>DOKU_BASE:</b><pre>'; 1175 print DOKU_BASE; 1176 print '</pre>'; 1177 1178 print '<b>abs DOKU_BASE:</b><pre>'; 1179 print DOKU_URL; 1180 print '</pre>'; 1181 1182 print '<b>rel DOKU_BASE:</b><pre>'; 1183 print dirname($_SERVER['PHP_SELF']).'/'; 1184 print '</pre>'; 1185 1186 print '<b>PHP Version:</b><pre>'; 1187 print phpversion(); 1188 print '</pre>'; 1189 1190 print '<b>locale:</b><pre>'; 1191 print setlocale(LC_ALL,0); 1192 print '</pre>'; 1193 1194 print '<b>encoding:</b><pre>'; 1195 print $lang['encoding']; 1196 print '</pre>'; 1197 1198 print '<b>Environment:</b><pre>'; 1199 print_r($_ENV); 1200 print '</pre>'; 1201 1202 print '<b>PHP settings:</b><pre>'; 1203 $inis = ini_get_all(); 1204 print_r($inis); 1205 print '</pre>'; 1206 1207 print '</body></html>'; 1208} 1209 1210/** 1211 * prints the acl-admin form(s) 1212 * 1213 * @author Frank Schubert <frank@schokilade.de> 1214 */ 1215function html_acl_admin(){ 1216 global $lang; 1217 global $ID; 1218 global $INFO; 1219 1220 print parsedLocale('acl_admin'); 1221?> 1222 <fieldset style="float:left; text-align:left; white-space:nowrap; width:320px;"> 1223 <legend><?=$lang['acl_admin']?></legend> 1224 1225 1226<!-- XXXXXXXXXXXXX --> 1227 1228 <form name="acl_admin_add" method="post" action="<?=wl($ID)?>" accept-charset="<?=$lang['encoding']?>"> 1229 <input type="hidden" name="do" value="acl_admin_add" /> 1230 <input type="hidden" name="save" value="1" /> 1231 <table> 1232 <tr> 1233 <td><?=$lang['acl_user']?></td> 1234 <td><input type="text" name="acl_user" class="edit" size="20" value="" /></td> 1235 </tr><tr> 1236 <td><?=$lang['acl_scope']?></td> 1237 <td><select name="acl_scope" id="acl_scope" class="edit" size="1" onChange="checkAclLevel();"> 1238 <option value="">(<?=$lang['acl_input_request']?>)</option> 1239 <option><?=$ID?></option> 1240 <?php if( ($ns=getNS($ID)) != NULL) {?> 1241 <option><?=$ns?>:*</option> 1242 <?php }else{ ?> 1243 <option>*</option> 1244 <?php } ?> 1245 </select></td> 1246 </tr><tr> 1247 <td style="vertical-align:top"><?=$lang['acl_level']?></td> 1248 <td> 1249 <input type="checkbox" name="acl_checkbox[1]" value="on" checked="checked" /><?=$lang['acl_read']?><br /> 1250 <input type="checkbox" name="acl_checkbox[2]" value="on" /><?=$lang['acl_edit']?><br /> 1251 <input type="checkbox" name="acl_checkbox[4]" value="on" /><?=$lang['acl_create']?><br /> 1252 <input type="checkbox" name="acl_checkbox[8]" value="on" /><?=$lang['acl_upload']?> 1253 </td> 1254 </tr><tr> 1255 <td></td> 1256 <td><input type="submit" class="button" value="<?=$lang['acl_commit']?>" /></td> 1257 </tr> 1258 </table> 1259 </form> 1260<!-- XXXXXXXXXXXXX --> 1261 </fieldset> 1262 1263 <div style="float:right;"> 1264 <fieldset> 1265 <legend><?=$lang['acl_current']?></legend> 1266 <div style="text-align:left"> 1267 1268<!-- XXXXXXXXXXXXX --> 1269 <?php 1270 $acl_config=get_acl_config($ID); 1271 foreach($acl_config as $pagename => $value){ 1272 if($pagename != '*') { 1273 $ID_cur=$pagename; 1274 while(($piece=getNS($ID_cur)) !== false){ 1275 $url="<a href='".wl($piece,'do=acl_admin')."'>".noNS($piece)."</a>:".$url;; 1276 $ID_cur=$piece; 1277 } 1278 $url.="<a href='".wl($pagename,'do=acl_admin')."'>".noNS($pagename)."</a>"; 1279 print $url; 1280 $url=''; 1281 }else{ 1282 print $pagename; 1283 } ?> 1284 1285 <!-- XXXXXXXXXXXXX --> 1286 <table class="inline"> 1287 <tr> 1288 <th class="inline"></th> 1289 <th class="inline">name</th> 1290 <th class="inline">R</th> 1291 <th class="inline">W</th> 1292 <th class="inline">C</th> 1293 <th class="inline">U</th> 1294 <th class="inline">UPDATE</th> 1295 <th class="inline">DELETE</th> 1296 </tr> 1297 <?php 1298 foreach($value as $conf){ 1299 ?> 1300 <tr> 1301 <!-- user/group --> 1302 <td class="inline"> 1303 <?php 1304 $group = false; 1305 if(substr($conf[0],0,1)=="@"){ 1306 print $lang['acl_group']; 1307 $group = true; 1308 }else{ 1309 print $lang['acl_user']; 1310 } 1311 ?> 1312 </td> 1313 <td class="inline"> 1314 <!-- name --> 1315 <?php 1316 if($group) { print substr($conf[0],1); } else { print $conf[0]; } 1317 ?> 1318 </td> 1319 <form name="acl_admin_change" method="post" action="<?=wl($ID)?>" accept-charset="<?=$lang['encoding']?>"> 1320 <?php 1321 // read,write,create,upload 1322 $acl_nums=array(1,2,4,8); 1323 foreach($acl_nums as $num){ 1324 ?><td class="inline"> 1325 <input type="hidden" name="do" value="acl_admin_change" /> 1326 <input type="hidden" name="save" value="1" /> 1327 <input type="hidden" name="acl_scope" value='<?=urlencode($pagename)?>' /> 1328 <input type="hidden" name="acl_user" value='<?=urlencode($conf[0])?>' /> 1329 <input type="hidden" name="acl_level" value='<?=$conf[1]?>' /> 1330 <input type="checkbox" name="acl_checkbox[<?=$num?>]" value="on"<?php 1331 if($conf[1]>=$num) { 1332 ?> checked="checked"<?php 1333 } 1334 ?> /></td><?php 1335 } 1336 ?> 1337 <td class="inline"><input type="submit" class="button" value="update"></td> 1338 </form> 1339 <td class="inline"> 1340 <!-- delete form --> 1341 <form name="acl_admin_del" method="post" action="<?=wl($ID)?>" accept-charset="<?=$lang['encoding']?>"> 1342 <input type="hidden" name="do" value="acl_admin_del" /> 1343 <input type="hidden" name="save" value="1" /> 1344 <input type="hidden" name="acl_scope" value='<?=urlencode($pagename);?>' /> 1345 <input type="hidden" name="acl_user" value='<?=urlencode($conf[0])?>' /> 1346 <input type="hidden" name="acl_level" value='<?=$conf[1]?>' /> 1347 <input type="submit" class="button" value='DEL' onClick="return window.confirm('<?=$lang['acl_confirm_delete']?>');" /> 1348 </form> 1349 </td> 1350 </tr> 1351 <?php 1352 } 1353 ?></table><?php 1354 } 1355 ?> 1356 </div> 1357 </fieldset> 1358 </div> 1359<? 1360} 1361 1362/** 1363 * Print the admin overview page 1364 * 1365 * @author Andreas Gohr <andi@splitbrain.org> 1366 */ 1367function html_admin(){ 1368 global $ID; 1369 global $lang; 1370 1371 print parsedLocale('admin'); 1372 1373 ptln('<ul class="admin">'); 1374 1375 // currently ACL only - more to come 1376 ptln('<li><a href="'.wl($ID,'do=admin&page=acl').'">'.$lang['admin_acl'].'</a></li>'); 1377 1378 ptln('</ul>'); 1379} 1380 1381?> 1382