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 11 require_once(DOKU_INC.'inc/parserutils.php'); 12 13/** 14 * Convenience function to quickly build a wikilink 15 * 16 * @author Andreas Gohr <andi@splitbrain.org> 17 */ 18function html_wikilink($id,$name=NULL,$search=''){ 19 static $xhtml_renderer = NULL; 20 if(is_null($xhtml_renderer)){ 21 require_once(DOKU_INC.'inc/parser/xhtml.php'); 22 $xhtml_renderer = new Doku_Renderer_xhtml(); 23 } 24 25 return $xhtml_renderer->internallink($id,$name,$search,true); 26} 27 28/** 29 * Helps building long attribute lists 30 * 31 * @author Andreas Gohr <andi@splitbrain.org> 32 */ 33function html_attbuild($attributes){ 34 $ret = ''; 35 foreach ( $attributes as $key => $value ) { 36 $ret .= $key.'="'.formtext($value).'" '; 37 } 38 return trim($ret); 39} 40 41/** 42 * The loginform 43 * 44 * @author Andreas Gohr <andi@splitbrain.org> 45 */ 46function html_login(){ 47 global $lang; 48 global $conf; 49 global $ID; 50 global $auth; 51 52 print p_locale_xhtml('login'); 53 ?> 54 <div class="centeralign"> 55 <form action="<?php echo script()?>" accept-charset="<?php echo $lang['encoding']?>" method="post"> 56 <fieldset> 57 <legend><?php echo $lang['btn_login']?></legend> 58 <input type="hidden" name="id" value="<?php echo $ID?>" /> 59 <input type="hidden" name="do" value="login" /> 60 <label class="block"> 61 <span><?php echo $lang['user']?></span> 62 <input type="text" name="u" value="<?php echo formText($_REQUEST['u'])?>" class="edit" /> 63 </label><br /> 64 <label class="block"> 65 <span><?php echo $lang['pass']?></span> 66 <input type="password" name="p" class="edit" /> 67 </label><br /> 68 <input type="submit" value="<?php echo $lang['btn_login']?>" class="button" /> 69 <label for="remember__me" class="simple"> 70 <input type="checkbox" name="r" id="remember__me" value="1" /> 71 <span><?php echo $lang['remember']?></span> 72 </label> 73 </fieldset> 74 </form> 75 <?php 76 if($auth->canDo('addUser') && $conf['openregister']){ 77 print '<p>'; 78 print $lang['reghere']; 79 print ': <a href="'.wl($ID,'do=register').'" class="wikilink1">'.$lang['register'].'</a>'; 80 print '</p>'; 81 } 82 83 if ($auth->canDo('modPass') && $conf['resendpasswd']) { 84 print '<p>'; 85 print $lang['pwdforget']; 86 print ': <a href="'.wl($ID,'do=resendpwd').'" class="wikilink1">'.$lang['btn_resendpwd'].'</a>'; 87 print '</p>'; 88 } 89 ?> 90 </div> 91 <?php 92/* 93 FIXME provide new hook 94 if(@file_exists('includes/login.txt')){ 95 print io_cacheParse('includes/login.txt'); 96 } 97*/ 98} 99 100/** 101 * shows the edit/source/show/draft button dependent on current mode 102 * 103 * @author Andreas Gohr <andi@splitbrain.org> 104 */ 105function html_editbutton(){ 106 global $ID; 107 global $REV; 108 global $ACT; 109 global $INFO; 110 111 if($ACT == 'show' || $ACT == 'search'){ 112 if($INFO['writable']){ 113 if($INFO['draft']){ 114 $r = html_btn('draft',$ID,'e',array('do' => 'draft'),'post'); 115 }else{ 116 if($INFO['exists']){ 117 $r = html_btn('edit',$ID,'e',array('do' => 'edit','rev' => $REV),'post'); 118 }else{ 119 $r = html_btn('create',$ID,'e',array('do' => 'edit','rev' => $REV),'post'); 120 } 121 } 122 }else{ 123 $r = html_btn('source',$ID,'v',array('do' => 'edit','rev' => $REV),'post'); 124 } 125 }else{ 126 $r = html_btn('show',$ID,'v',array('do' => 'show')); 127 } 128 return $r; 129} 130 131/** 132 * prints a section editing button 133 * 134 * @author Andreas Gohr <andi@splitbrain.org> 135 */ 136function html_secedit_button($section,$p){ 137 global $ID; 138 global $lang; 139 global $INFO; 140 $secedit = ''; 141# if($p) $secedit .= "</p>\n"; 142 $secedit .= '<div class="secedit">'; 143 $secedit .= html_btn('secedit',$ID,'', 144 array('do' => 'edit', 145 'lines' => "$section", 146 'rev' => $INFO['lastmod']), 147 'post'); 148 $secedit .= '</div>'; 149# if($p) $secedit .= "\n<p>"; 150 return $secedit; 151} 152 153/** 154 * inserts section edit buttons if wanted or removes the markers 155 * 156 * @author Andreas Gohr <andi@splitbrain.org> 157 */ 158function html_secedit($text,$show=true){ 159 global $INFO; 160 if($INFO['writable'] && $show && !$INFO['rev']){ 161 $text = preg_replace('#<!-- SECTION \[(\d+-\d+)\] -->#e', 162 "html_secedit_button('\\1',true)", 163 $text); 164 $text = preg_replace('#<!-- SECTION \[(\d+-)\] -->#e', 165 "html_secedit_button('\\1',false)", 166 $text); 167 }else{ 168 $text = preg_replace('#<!-- SECTION \[(\d*-\d*)\] -->#e','',$text); 169 } 170 return $text; 171} 172 173/** 174 * Just the back to top button (in its own form) 175 * 176 * @author Andreas Gohr <andi@splitbrain.org> 177 */ 178function html_topbtn(){ 179 global $lang; 180 181 $ret = ''; 182 $ret = '<a class="nolink" href="#dokuwiki__top"><input type="button" class="button" value="'.$lang['btn_top'].'" onclick="window.scrollTo(0, 0)" /></a>'; 183 184 return $ret; 185} 186 187/** 188 * Just the back to media window button in its own form 189 * 190 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 191 */ 192function html_backtomedia_button($params,$akey=''){ 193 global $conf; 194 global $lang; 195 196 $ret = '<form class="button" method="get" action="'.DOKU_BASE.'lib/exe/mediamanager.php"><div class="no">'; 197 198 reset($params); 199 while (list($key, $val) = each($params)) { 200 $ret .= '<input type="hidden" name="'.$key.'" '; 201 $ret .= 'value="'.htmlspecialchars($val).'" />'; 202 } 203 204 $ret .= '<input type="submit" value="'.htmlspecialchars($lang['btn_backtomedia']).'" class="button" '; 205 if($akey){ 206 $ret .= 'title="ALT+'.strtoupper($akey).'" '; 207 $ret .= 'accesskey="'.$akey.'" '; 208 } 209 $ret .= '/>'; 210 $ret .= '</div></form>'; 211 212 return $ret; 213} 214 215/** 216 * Displays a button (using its own form) 217 * 218 * @author Andreas Gohr <andi@splitbrain.org> 219 */ 220function html_btn($name,$id,$akey,$params,$method='get'){ 221 global $conf; 222 global $lang; 223 224 $label = $lang['btn_'.$name]; 225 226 $ret = ''; 227 228 //filter id (without urlencoding) 229 $id = idfilter($id,false); 230 231 //make nice URLs even for buttons 232 if($conf['userewrite'] == 2){ 233 $script = DOKU_BASE.DOKU_SCRIPT.'/'.$id; 234 }elseif($conf['userewrite']){ 235 $script = DOKU_BASE.$id; 236 }else{ 237 $script = DOKU_BASE.DOKU_SCRIPT; 238 $params['id'] = $id; 239 } 240 241 $ret .= '<form class="button" method="'.$method.'" action="'.$script.'"><div class="no">'; 242 243 if(is_array($params)){ 244 reset($params); 245 while (list($key, $val) = each($params)) { 246 $ret .= '<input type="hidden" name="'.$key.'" '; 247 $ret .= 'value="'.htmlspecialchars($val).'" />'; 248 } 249 } 250 251 $ret .= '<input type="submit" value="'.htmlspecialchars($label).'" class="button" '; 252 if($akey){ 253 $ret .= 'title="[ALT+'.strtoupper($akey).']" '; 254 $ret .= 'accesskey="'.$akey.'" '; 255 } 256 $ret .= '/>'; 257 $ret .= '</div></form>'; 258 259 return $ret; 260} 261 262/** 263 * show a wiki page 264 * 265 * @author Andreas Gohr <andi@splitbrain.org> 266 */ 267function html_show($txt=''){ 268 global $ID; 269 global $REV; 270 global $HIGH; 271 //disable section editing for old revisions or in preview 272 if($txt || $REV){ 273 $secedit = false; 274 }else{ 275 $secedit = true; 276 } 277 278 if ($txt){ 279 //PreviewHeader 280 print '<br id="scroll__here" />'; 281 print p_locale_xhtml('preview'); 282 print '<div class="preview">'; 283 print html_secedit(p_render('xhtml',p_get_instructions($txt),$info),$secedit); 284 print '<div class="clearer"></div>'; 285 print '</div>'; 286 287 }else{ 288 if ($REV) print p_locale_xhtml('showrev'); 289 $html = p_wiki_xhtml($ID,$REV,true); 290 $html = html_secedit($html,$secedit); 291 print html_hilight($html,$HIGH); 292 } 293} 294 295/** 296 * ask the user about how to handle an exisiting draft 297 * 298 * @author Andreas Gohr <andi@splitbrain.org> 299 */ 300function html_draft(){ 301 global $INFO; 302 global $ID; 303 global $lang; 304 global $conf; 305 $draft = unserialize(io_readFile($INFO['draft'],false)); 306 $text = cleanText(con($draft['prefix'],$draft['text'],$draft['suffix'],true)); 307 308 echo p_locale_xhtml('draft'); 309 ?> 310 <form id="dw__editform" method="post" action="<?php echo script()?>" 311 accept-charset="<?php echo $lang['encoding']?>"><div class="no"> 312 <input type="hidden" name="id" value="<?php echo $ID?>" /> 313 <input type="hidden" name="date" value="<?php echo $draft['date']?>" /></div> 314 <textarea name="wikitext" id="wiki__text" readonly="readonly" cols="80" rows="10" class="edit"><?php echo "\n".formText($text)?></textarea> 315 316 <div id="draft__status"><?php echo $lang['draftdate'].' '.date($conf['dformat'],filemtime($INFO['draft']))?></div> 317 318 <input class="button" type="submit" name="do" value="<?php echo $lang['btn_recover']?>" tabindex="1" /> 319 <input class="button" type="submit" name="do" value="<?php echo $lang['btn_draftdel']?>" tabindex="2" /> 320 <input class="button" type="submit" name="do" value="<?php echo $lang['btn_cancel']?>" tabindex="3" /> 321 </form> 322 <?php 323} 324 325/** 326 * Highlights searchqueries in HTML code 327 * 328 * @author Andreas Gohr <andi@splitbrain.org> 329 * @author Harry Fuecks <hfuecks@gmail.com> 330 */ 331function html_hilight($html,$query){ 332 //split at common delimiters 333 $queries = preg_split ('/[\s\'"\\\\`()\]\[?:!\.{};,#+*<>\\/]+/',$query,-1,PREG_SPLIT_NO_EMPTY); 334 foreach ($queries as $q){ 335 $q = preg_quote($q,'/'); 336 $html = preg_replace_callback("/((<[^>]*)|$q)/i",'html_hilight_callback',$html); 337 } 338 return $html; 339} 340 341/** 342 * Callback used by html_hilight() 343 * 344 * @author Harry Fuecks <hfuecks@gmail.com> 345 */ 346function html_hilight_callback($m) { 347 $hlight = unslash($m[0]); 348 if ( !isset($m[2])) { 349 $hlight = '<span class="search_hit">'.$hlight.'</span>'; 350 } 351 return $hlight; 352} 353 354/** 355 * Run a search and display the result 356 * 357 * @author Andreas Gohr <andi@splitbrain.org> 358 */ 359function html_search(){ 360 require_once(DOKU_INC.'inc/search.php'); 361 require_once(DOKU_INC.'inc/fulltext.php'); 362 global $conf; 363 global $QUERY; 364 global $ID; 365 global $lang; 366 367 print p_locale_xhtml('searchpage'); 368 flush(); 369 370 //check if search is restricted to namespace 371 if(preg_match('/([^@]*)@([^@]*)/',$QUERY,$match)) { 372 $id = cleanID($match[1]); 373 if(empty($id)) { 374 print '<div class="nothing">'.$lang['nothingfound'].'</div>'; 375 flush(); 376 return; 377 } 378 } else { 379 $id = cleanID($QUERY); 380 } 381 382 //show progressbar 383 print '<div class="centeralign" id="dw__loading">'; 384 print '<br /></div>'; 385 print '<script type="text/javascript" charset="utf-8">'; 386 print 'showLoadBar("dw__loading");'; 387 print '</script>'; 388 flush(); 389 390 //do quick pagesearch 391 $data = array(); 392 393 $data = ft_pageLookup($id); 394 if(count($data)){ 395 sort($data); 396 print '<div class="search_quickresult">'; 397 print '<h3>'.$lang[quickhits].':</h3>'; 398 print '<ul class="search_quickhits">'; 399 foreach($data as $id){ 400 print '<li> '; 401 print html_wikilink(':'.$id,$conf['useheading']?NULL:$id); 402 print '</li> '; 403 } 404 print '</ul> '; 405 //clear float (see http://www.complexspiral.com/publications/containing-floats/) 406 print '<div class="clearer"> </div>'; 407 print '</div>'; 408 } 409 flush(); 410 411 //do fulltext search 412 $data = ft_pageSearch($QUERY,$poswords); 413 if(count($data)){ 414 $num = 1; 415 foreach($data as $id => $cnt){ 416 print '<div class="search_result">'; 417 print html_wikilink(':'.$id,$conf['useheading']?NULL:$id,$poswords); 418 print ': <span class="search_cnt">'.$cnt.' '.$lang['hits'].'</span><br />'; 419 if($num < 15){ // create snippets for the first number of matches only #FIXME add to conf ? 420 print '<div class="search_snippet">'.ft_snippet($id,$poswords).'</div>'; 421 } 422 print '</div>'; 423 flush(); 424 $num++; 425 } 426 }else{ 427 print '<div class="nothing">'.$lang['nothingfound'].'</div>'; 428 } 429 430 //hide progressbar 431 print '<script type="text/javascript" charset="utf-8">'; 432 print 'hideLoadBar("dw__loading");'; 433 print '</script>'; 434 flush(); 435} 436 437/** 438 * Display error on locked pages 439 * 440 * @author Andreas Gohr <andi@splitbrain.org> 441 */ 442function html_locked(){ 443 global $ID; 444 global $conf; 445 global $lang; 446 global $INFO; 447 448 $locktime = filemtime(wikiFN($ID).'.lock'); 449 $expire = @date($conf['dformat'], $locktime + $conf['locktime'] ); 450 $min = round(($conf['locktime'] - (time() - $locktime) )/60); 451 452 print p_locale_xhtml('locked'); 453 print '<ul>'; 454 print '<li><div class="li"><strong>'.$lang['lockedby'].':</strong> '.$INFO['locked'].'</li>'; 455 print '<li><div class="li"><strong>'.$lang['lockexpire'].':</strong> '.$expire.' ('.$min.' min)</div></li>'; 456 print '</ul>'; 457} 458 459/** 460 * list old revisions 461 * 462 * @author Andreas Gohr <andi@splitbrain.org> 463 */ 464function html_revisions(){ 465 global $ID; 466 global $INFO; 467 global $conf; 468 global $lang; 469 $revisions = getRevisions($ID); 470 $date = @date($conf['dformat'],$INFO['lastmod']); 471 472 print p_locale_xhtml('revisions'); 473 print '<ul>'; 474 if($INFO['exists']){ 475 print ($INFO['minor']) ? '<li class="minor">' : '<li>'; 476 print '<div class="li">'; 477 478 print $date; 479 480 print ' <img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" /> '; 481 482 print '<a class="wikilink1" href="'.wl($ID).'">'.$ID.'</a> '; 483 484 print $INFO['sum']; 485 print ' <span class="user">'; 486 print $INFO['editor']; 487 print '</span> '; 488 489 print '('.$lang['current'].')'; 490 print '</div>'; 491 print '</li>'; 492 } 493 494 foreach($revisions as $rev){ 495 $date = date($conf['dformat'],$rev); 496 $info = getRevisionInfo($ID,$rev); 497 498 print ($info['minor']) ? '<li class="minor">' : '<li>'; 499 print '<div class="li">'; 500 print $date; 501 502 print ' <a href="'.wl($ID,"rev=$rev,do=diff").'">'; 503 $p = array(); 504 $p['src'] = DOKU_BASE.'lib/images/diff.png'; 505 $p['width'] = 15; 506 $p['height'] = 11; 507 $p['title'] = $lang['diff']; 508 $p['alt'] = $lang['diff']; 509 $att = buildAttributes($p); 510 print "<img $att />"; 511 print '</a> '; 512 513 print '<a class="wikilink1" href="'.wl($ID,"rev=$rev").'">'.$ID.'</a> '; 514 515 print htmlspecialchars($info['sum']); 516 print ' <span class="user">'; 517 if($info['user']){ 518 print $info['user']; 519 }else{ 520 print $info['ip']; 521 } 522 print '</span>'; 523 524 print '</div>'; 525 print '</li>'; 526 } 527 print '</ul>'; 528} 529 530/** 531 * display recent changes 532 * 533 * @author Andreas Gohr <andi@splitbrain.org> 534 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 535 */ 536function html_recent($first=0){ 537 global $conf; 538 global $lang; 539 global $ID; 540 /* we need to get one additionally log entry to be able to 541 * decide if this is the last page or is there another one. 542 * This is the cheapest solution to get this information. 543 */ 544 $recents = getRecents($first,$conf['recent'] + 1,getNS($ID)); 545 if(count($recents) == 0 && $first != 0){ 546 $first=0; 547 $recents = getRecents(0,$conf['recent'] + 1,getNS($ID)); 548 } 549 $cnt = count($recents) <= $conf['recent'] ? count($recents) : $conf['recent']; 550 551 print p_locale_xhtml('recent'); 552 print '<ul>'; 553 554 foreach($recents as $recent){ 555 $date = date($conf['dformat'],$recent['date']); 556 print ($recent['minor']) ? '<li class="minor">' : '<li>'; 557 print '<div class="li">'; 558 559 print $date.' '; 560 561 print '<a href="'.wl($recent['id'],"do=diff").'">'; 562 $p = array(); 563 $p['src'] = DOKU_BASE.'lib/images/diff.png'; 564 $p['width'] = 15; 565 $p['height'] = 11; 566 $p['title'] = $lang['diff']; 567 $p['alt'] = $lang['diff']; 568 $att = buildAttributes($p); 569 print "<img $att />"; 570 print '</a> '; 571 572 print '<a href="'.wl($recent['id'],"do=revisions").'">'; 573 $p = array(); 574 $p['src'] = DOKU_BASE.'lib/images/history.png'; 575 $p['width'] = 12; 576 $p['height'] = 14; 577 $p['title'] = $lang['btn_revs']; 578 $p['alt'] = $lang['btn_revs']; 579 $att = buildAttributes($p); 580 print "<img $att />"; 581 print '</a> '; 582 583 print html_wikilink(':'.$recent['id'],$conf['useheading']?NULL:$recent['id']); 584 print ' '.htmlspecialchars($recent['sum']); 585 586 print ' <span class="user">'; 587 if($recent['user']){ 588 print $recent['user']; 589 }else{ 590 print $recent['ip']; 591 } 592 print '</span>'; 593 594 print '</div>'; 595 print '</li>'; 596 } 597 print '</ul>'; 598 599 print '<div class="pagenav">'; 600 $last = $first + $conf['recent']; 601 if ($first > 0) { 602 $first -= $conf['recent']; 603 if ($first < 0) $first = 0; 604 print '<div class="pagenav-prev">'; 605 print html_btn('newer','',"p",array('do' => 'recent', 'first' => $first)); 606 print '</div>'; 607 } 608 if ($conf['recent'] < count($recents)) { 609 print '<div class="pagenav-next">'; 610 print html_btn('older','',"n",array('do' => 'recent', 'first' => $last)); 611 print '</div>'; 612 } 613 print '</div>'; 614} 615 616/** 617 * Display page index 618 * 619 * @author Andreas Gohr <andi@splitbrain.org> 620 */ 621function html_index($ns){ 622 require_once(DOKU_INC.'inc/search.php'); 623 global $conf; 624 global $ID; 625 $dir = $conf['datadir']; 626 $ns = cleanID($ns); 627 #fixme use appropriate function 628 if(empty($ns)){ 629 $ns = dirname(str_replace(':','/',$ID)); 630 if($ns == '.') $ns =''; 631 } 632 $ns = utf8_encodeFN(str_replace(':','/',$ns)); 633 634 print p_locale_xhtml('index'); 635 636 $data = array(); 637 search($data,$conf['datadir'],'search_index',array('ns' => $ns)); 638 print html_buildlist($data,'idx','html_list_index','html_li_index'); 639} 640 641/** 642 * Index item formatter 643 * 644 * User function for html_buildlist() 645 * 646 * @author Andreas Gohr <andi@splitbrain.org> 647 */ 648function html_list_index($item){ 649 $ret = ''; 650 $base = ':'.$item['id']; 651 $base = substr($base,strrpos($base,':')+1); 652 if($item['type']=='d'){ 653 $ret .= '<a href="'.wl($ID,'idx='.$item['id']).'" class="idx_dir">'; 654 $ret .= $base; 655 $ret .= '</a>'; 656 }else{ 657 $ret .= html_wikilink(':'.$item['id']); 658 } 659 return $ret; 660} 661 662/** 663 * Index List item 664 * 665 * This user function is used in html_build_lidt to build the 666 * <li> tags for namespaces when displaying the page index 667 * it gives different classes to opened or closed "folders" 668 * 669 * @author Andreas Gohr <andi@splitbrain.org> 670 */ 671function html_li_index($item){ 672 if($item['type'] == "f"){ 673 return '<li class="level'.$item['level'].'">'; 674 }elseif($item['open']){ 675 return '<li class="open">'; 676 }else{ 677 return '<li class="closed">'; 678 } 679} 680 681/** 682 * Default List item 683 * 684 * @author Andreas Gohr <andi@splitbrain.org> 685 */ 686function html_li_default($item){ 687 return '<li class="level'.$item['level'].'">'; 688} 689 690/** 691 * Build an unordered list 692 * 693 * Build an unordered list from the given $data array 694 * Each item in the array has to have a 'level' property 695 * the item itself gets printed by the given $func user 696 * function. The second and optional function is used to 697 * print the <li> tag. Both user function need to accept 698 * a single item. 699 * 700 * Both user functions can be given as array to point to 701 * a member of an object. 702 * 703 * @author Andreas Gohr <andi@splitbrain.org> 704 */ 705function html_buildlist($data,$class,$func,$lifunc='html_li_default'){ 706 $level = 0; 707 $opens = 0; 708 $ret = ''; 709 710 foreach ($data as $item){ 711 712 if( $item['level'] > $level ){ 713 //open new list 714 for($i=0; $i<($item['level'] - $level); $i++){ 715 if ($i) $ret .= "<li class=\"clear\">\n"; 716 $ret .= "\n<ul class=\"$class\">\n"; 717 } 718 }elseif( $item['level'] < $level ){ 719 //close last item 720 $ret .= "</li>\n"; 721 for ($i=0; $i<($level - $item['level']); $i++){ 722 //close higher lists 723 $ret .= "</ul>\n</li>\n"; 724 } 725 }else{ 726 //close last item 727 $ret .= "</li>\n"; 728 } 729 730 //remember current level 731 $level = $item['level']; 732 733 //print item 734 if(is_array($lifunc)){ 735 $ret .= $lifunc[0]->$lifunc[1]($item); //user object method 736 }else{ 737 $ret .= $lifunc($item); //user function 738 } 739 $ret .= '<div class="li">'; 740 if(is_array($func)){ 741 $ret .= $func[0]->$func[1]($item); //user object method 742 }else{ 743 $ret .= $func($item); //user function 744 } 745 $ret .= '</div>'; 746 } 747 748 //close remaining items and lists 749 for ($i=0; $i < $level; $i++){ 750 $ret .= "</li></ul>\n"; 751 } 752 753 return $ret; 754} 755 756/** 757 * display backlinks 758 * 759 * @author Andreas Gohr <andi@splitbrain.org> 760 */ 761function html_backlinks(){ 762 require_once(DOKU_INC.'inc/fulltext.php'); 763 global $ID; 764 global $conf; 765 766 print p_locale_xhtml('backlinks'); 767 768 $data = ft_backlinks($ID); 769 770 print '<ul class="idx">'; 771 foreach($data as $blink){ 772 print '<li><div class="li">'; 773 print html_wikilink(':'.$blink,$conf['useheading']?NULL:$blink); 774 print '</div></li>'; 775 } 776 print '</ul>'; 777} 778 779/** 780 * show diff 781 * 782 * @author Andreas Gohr <andi@splitbrain.org> 783 */ 784function html_diff($text='',$intro=true){ 785 require_once(DOKU_INC.'inc/DifferenceEngine.php'); 786 global $ID; 787 global $REV; 788 global $lang; 789 global $conf; 790 if($text){ 791 $df = new Diff(split("\n",htmlspecialchars(rawWiki($ID,''))), 792 split("\n",htmlspecialchars(cleanText($text)))); 793 $left = '<a class="wikilink1" href="'.wl($ID).'">'. 794 $ID.' '.date($conf['dformat'],@filemtime(wikiFN($ID))).'</a>'. 795 $lang['current']; 796 $right = $lang['yours']; 797 }else{ 798 if($REV){ 799 $r = $REV; 800 }else{ 801 //use last revision if none given 802 $revs = getRevisions($ID); 803 $r = $revs[0]; 804 } 805 806 $df = new Diff(split("\n",htmlspecialchars(rawWiki($ID,$r))), 807 split("\n",htmlspecialchars(rawWiki($ID,'')))); 808 $left = '<a class="wikilink1" href="'.wl($ID,"rev=$r").'">'. 809 $ID.' '.date($conf['dformat'],$r).'</a>'; 810 $right = '<a class="wikilink1" href="'.wl($ID).'">'. 811 $ID.' '.date($conf['dformat'],@filemtime(wikiFN($ID))).'</a> '. 812 $lang['current']; 813 } 814 $tdf = new TableDiffFormatter(); 815 if($intro) print p_locale_xhtml('diff'); 816 ?> 817 <table class="diff"> 818 <tr> 819 <th colspan="2"> 820 <?php echo $left?> 821 </th> 822 <th colspan="2"> 823 <?php echo $right?> 824 </th> 825 </tr> 826 <?php echo $tdf->format($df)?> 827 </table> 828 <?php 829} 830 831/** 832 * show warning on conflict detection 833 * 834 * @author Andreas Gohr <andi@splitbrain.org> 835 */ 836function html_conflict($text,$summary){ 837 global $ID; 838 global $lang; 839 840 print p_locale_xhtml('conflict'); 841 ?> 842 <form id="dw__editform" method="post" action="<?php echo script()?>" accept-charset="<?php echo $lang['encoding']?>"> 843 <div class="centeralign"> 844 <input type="hidden" name="id" value="<?php echo $ID?>" /> 845 <input type="hidden" name="wikitext" value="<?php echo formText($text)?>" /> 846 <input type="hidden" name="summary" value="<?php echo formText($summary)?>" /> 847 848 <input class="button" type="submit" name="do" value="<?php echo $lang['btn_save']?>" accesskey="s" title="[ALT+S]" /> 849 <input class="button" type="submit" name="do" value="<?php echo $lang['btn_cancel']?>" /> 850 </div> 851 </form> 852 <br /><br /><br /><br /> 853 <?php 854} 855 856/** 857 * Prints the global message array 858 * 859 * @author Andreas Gohr <andi@splitbrain.org> 860 */ 861function html_msgarea(){ 862 global $MSG; 863 864 if(!isset($MSG)) return; 865 866 foreach($MSG as $msg){ 867 print '<div class="'.$msg['lvl'].'">'; 868 print $msg['msg']; 869 print '</div>'; 870 } 871} 872 873/** 874 * Prints the registration form 875 * 876 * @author Andreas Gohr <andi@splitbrain.org> 877 */ 878function html_register(){ 879 global $lang; 880 global $conf; 881 global $ID; 882 883 print p_locale_xhtml('register'); 884?> 885 <div class="centeralign"> 886 <form id="dw__register" method="post" action="<?php echo wl($ID)?>" accept-charset="<?php echo $lang['encoding']?>"> 887 <fieldset> 888 <input type="hidden" name="do" value="register" /> 889 <input type="hidden" name="save" value="1" /> 890 891 <legend><?php echo $lang['register']?></legend> 892 <label class="block"> 893 <?php echo $lang['user']?> 894 <input type="text" name="login" class="edit" size="50" value="<?php echo formText($_POST['login'])?>" /> 895 </label><br /> 896 897 <?php 898 if (!$conf['autopasswd']) { 899 ?> 900 <label class="block"> 901 <?php echo $lang['pass']?> 902 <input type="password" name="pass" class="edit" size="50" /> 903 </label><br /> 904 <label class="block"> 905 <?php echo $lang['passchk']?> 906 <input type="password" name="passchk" class="edit" size="50" /> 907 </label><br /> 908 <?php 909 } 910 ?> 911 912 <label class="block"> 913 <?php echo $lang['fullname']?> 914 <input type="text" name="fullname" class="edit" size="50" value="<?php echo formText($_POST['fullname'])?>" /> 915 </label><br /> 916 <label class="block"> 917 <?php echo $lang['email']?> 918 <input type="text" name="email" class="edit" size="50" value="<?php echo formText($_POST['email'])?>" /> 919 </label><br /> 920 <input type="submit" class="button" value="<?php echo $lang['register']?>" /> 921 </fieldset> 922 </form> 923 </div> 924<?php 925} 926 927/** 928 * Print the update profile form 929 * 930 * @author Christopher Smith <chris@jalakai.co.uk> 931 * @author Andreas Gohr <andi@splitbrain.org> 932 */ 933function html_updateprofile(){ 934 global $lang; 935 global $conf; 936 global $ID; 937 global $INFO; 938 global $auth; 939 940 print p_locale_xhtml('updateprofile'); 941 942 if (empty($_POST['fullname'])) $_POST['fullname'] = $INFO['userinfo']['name']; 943 if (empty($_POST['email'])) $_POST['email'] = $INFO['userinfo']['mail']; 944?> 945 <div class="centeralign"> 946 <form id="dw__register" method="post" action="<?php echo wl($ID)?>" accept-charset="<?php echo $lang['encoding']?>"> 947 <fieldset style="width: 80%;"> 948 <input type="hidden" name="do" value="profile" /> 949 <input type="hidden" name="save" value="1" /> 950 951 <legend><?php echo $lang['profile']?></legend> 952 <label class="block"> 953 <?php echo $lang['user']?> 954 <input type="text" name="fullname" disabled="disabled" class="edit" size="50" value="<?php echo formText($_SERVER['REMOTE_USER'])?>" /> 955 </label><br /> 956 <label class="block"> 957 <?php echo $lang['fullname']?> 958 <input type="text" name="fullname" <?php if(!$auth->canDo('modName')) echo 'disabled="disabled"'?> class="edit" size="50" value="<?php echo formText($_POST['fullname'])?>" /> 959 </label><br /> 960 <label class="block"> 961 <?php echo $lang['email']?> 962 <input type="text" name="email" <?php if(!$auth->canDo('modName')) echo 'disabled="disabled"'?> class="edit" size="50" value="<?php echo formText($_POST['email'])?>" /> 963 </label><br /><br /> 964 965 <?php if($auth->canDo('modPass')) { ?> 966 <label class="block"> 967 <?php echo $lang['newpass']?> 968 <input type="password" name="newpass" class="edit" size="50" /> 969 </label><br /> 970 <label class="block"> 971 <?php echo $lang['passchk']?> 972 <input type="password" name="passchk" class="edit" size="50" /> 973 </label><br /> 974 <?php } ?> 975 976 <?php if ($conf['profileconfirm']) { ?> 977 <br /> 978 <label class="block"> 979 <?php echo $lang['oldpass']?> 980 <input type="password" name="oldpass" class="edit" size="50" /> 981 </label><br /> 982 <?php } ?> 983 984 <input type="submit" class="button" value="<?php echo $lang['btn_save']?>" /> 985 <input type="reset" class="button" value="<?php echo $lang['btn_reset']?>" /> 986 </fieldset> 987 </form> 988 </div> 989<?php 990} 991 992/** 993 * This displays the edit form (lots of logic included) 994 * 995 * @fixme this is a huge lump of code and should be modularized 996 * @author Andreas Gohr <andi@splitbrain.org> 997 */ 998function html_edit($text=null,$include='edit'){ //FIXME: include needed? 999 global $ID; 1000 global $REV; 1001 global $DATE; 1002 global $RANGE; 1003 global $PRE; 1004 global $SUF; 1005 global $INFO; 1006 global $SUM; 1007 global $lang; 1008 global $conf; 1009 1010 //set summary default 1011 if(!$SUM){ 1012 if($REV){ 1013 $SUM = $lang['restored']; 1014 }elseif(!$INFO['exists']){ 1015 $SUM = $lang['created']; 1016 } 1017 } 1018 1019 //no text? Load it! 1020 if(!isset($text)){ 1021 $pr = false; //no preview mode 1022 if($INFO['exists']){ 1023 if($RANGE){ 1024 list($PRE,$text,$SUF) = rawWikiSlices($RANGE,$ID,$REV); 1025 }else{ 1026 $text = rawWiki($ID,$REV); 1027 } 1028 }else{ 1029 //try to load a pagetemplate 1030 $text = pageTemplate($ID); 1031 } 1032 }else{ 1033 $pr = true; //preview mode 1034 } 1035 1036 $wr = $INFO['writable']; 1037 if($wr){ 1038 if ($REV) print p_locale_xhtml('editrev'); 1039 print p_locale_xhtml($include); 1040 }else{ 1041 print p_locale_xhtml('read'); 1042 $ro='readonly="readonly"'; 1043 } 1044 if(!$DATE) $DATE = $INFO['lastmod']; 1045 1046 1047?> 1048 <div style="width:99%;"> 1049 1050 <div class="toolbar"> 1051 <div id="draft__status"><?php if($INFO['draft']) echo $lang['draftdate'].' '.date($conf['dformat']);?></div> 1052 <div id="tool__bar"><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>" 1053 target="_blank"><?php echo $lang['mediaselect'] ?></a></div> 1054 1055 <?php if($wr){?> 1056 <script type="text/javascript" charset="utf-8"> 1057 <?php /* sets changed to true when previewed */?> 1058 textChanged = <?php ($pr) ? print 'true' : print 'false' ?>; 1059 </script> 1060 <span id="spell__action"></span> 1061 <div id="spell__suggest"></div> 1062 <?php } ?> 1063 </div> 1064 <div id="spell__result"></div> 1065 1066 1067 <form id="dw__editform" method="post" action="<?php echo script()?>" accept-charset="<?php echo $lang['encoding']?>"><div class="no"> 1068 <input type="hidden" name="id" value="<?php echo $ID?>" /> 1069 <input type="hidden" name="rev" value="<?php echo $REV?>" /> 1070 <input type="hidden" name="date" value="<?php echo $DATE?>" /> 1071 <input type="hidden" name="prefix" value="<?php echo formText($PRE)?>" /> 1072 <input type="hidden" name="suffix" value="<?php echo formText($SUF)?>" /> 1073 </div> 1074 1075 <textarea name="wikitext" id="wiki__text" <?php echo $ro?> cols="80" rows="10" class="edit" tabindex="1"><?php echo "\n".formText($text)?></textarea> 1076 1077 <div id="wiki__editbar"> 1078 <div id="size__ctl"></div> 1079 <?php if($wr){?> 1080 <div class="editButtons"> 1081 <input class="button" id="edbtn__save" type="submit" name="do" value="<?php echo $lang['btn_save']?>" accesskey="s" title="[ALT+S]" tabindex="4" /> 1082 <input class="button" id="edbtn__preview" type="submit" name="do" value="<?php echo $lang['btn_preview']?>" accesskey="p" title="[ALT+P]" tabindex="5" /> 1083 <input class="button" type="submit" name="do[draftdel]" value="<?php echo $lang['btn_cancel']?>" tabindex="6" /> 1084 </div> 1085 <?php } ?> 1086 <?php if($wr){ ?> 1087 <div class="summary"> 1088 <label for="edit__summary" class="nowrap"><?php echo $lang['summary']?>:</label> 1089 <input type="text" class="edit" name="summary" id="edit__summary" size="50" value="<?php echo formText($SUM)?>" tabindex="2" /> 1090 <?php html_minoredit()?> 1091 </div> 1092 <?php }?> 1093 </div> 1094 </form> 1095 </div> 1096<?php 1097} 1098 1099/** 1100 * Adds a checkbox for minor edits for logged in users 1101 * 1102 * @author Andrea Gohr <andi@splitbrain.org> 1103 */ 1104function html_minoredit(){ 1105 global $conf; 1106 global $lang; 1107 // minor edits are for logged in users only 1108 if(!$conf['useacl'] || !$_SERVER['REMOTE_USER']){ 1109 return; 1110 } 1111 1112 $p = array(); 1113 $p['name'] = 'minor'; 1114 $p['type'] = 'checkbox'; 1115 $p['id'] = 'minoredit'; 1116 $p['tabindex'] = 3; 1117 $p['value'] = '1'; 1118 if($_REQUEST['minor']) $p['checked']='checked'; 1119 $att = buildAttributes($p); 1120 1121 print '<span class="nowrap">'; 1122 print "<input $att />"; 1123 print '<label for="minoredit">'; 1124 print $lang['minoredit']; 1125 print '</label>'; 1126 print '</span>'; 1127} 1128 1129/** 1130 * prints some debug info 1131 * 1132 * @author Andreas Gohr <andi@splitbrain.org> 1133 */ 1134function html_debug(){ 1135 global $conf; 1136 global $lang; 1137 global $auth; 1138 //remove sensitive data 1139 $cnf = $conf; 1140 $cnf['auth']='***'; 1141 $cnf['notify']='***'; 1142 $cnf['ftp']='***'; 1143 1144 print '<html><body>'; 1145 1146 print '<p>When reporting bugs please send all the following '; 1147 print 'output as a mail to andi@splitbrain.org '; 1148 print 'The best way to do this is to save this page in your browser</p>'; 1149 1150 print '<b>$_SERVER:</b><pre>'; 1151 print_r($_SERVER); 1152 print '</pre>'; 1153 1154 print '<b>$conf:</b><pre>'; 1155 print_r($cnf); 1156 print '</pre>'; 1157 1158 print '<b>DOKU_BASE:</b><pre>'; 1159 print DOKU_BASE; 1160 print '</pre>'; 1161 1162 print '<b>abs DOKU_BASE:</b><pre>'; 1163 print DOKU_URL; 1164 print '</pre>'; 1165 1166 print '<b>rel DOKU_BASE:</b><pre>'; 1167 print dirname($_SERVER['PHP_SELF']).'/'; 1168 print '</pre>'; 1169 1170 print '<b>PHP Version:</b><pre>'; 1171 print phpversion(); 1172 print '</pre>'; 1173 1174 print '<b>locale:</b><pre>'; 1175 print setlocale(LC_ALL,0); 1176 print '</pre>'; 1177 1178 print '<b>encoding:</b><pre>'; 1179 print $lang['encoding']; 1180 print '</pre>'; 1181 1182 if($auth){ 1183 print '<b>Auth backend capabilities:</b><pre>'; 1184 print_r($auth->cando); 1185 print '</pre>'; 1186 } 1187 1188 print '<b>$_SESSION:</b><pre>'; 1189 print_r($_SESSION); 1190 print '</pre>'; 1191 1192 print '<b>Environment:</b><pre>'; 1193 print_r($_ENV); 1194 print '</pre>'; 1195 1196 print '<b>PHP settings:</b><pre>'; 1197 $inis = ini_get_all(); 1198 print_r($inis); 1199 print '</pre>'; 1200 1201 print '</body></html>'; 1202} 1203 1204function html_admin(){ 1205 global $ID; 1206 global $lang; 1207 global $conf; 1208 1209 print p_locale_xhtml('admin'); 1210 1211 // build menu of admin functions from the plugins that handle them 1212 $pluginlist = plugin_list('admin'); 1213 $menu = array(); 1214 foreach ($pluginlist as $p) { 1215 if($obj =& plugin_load('admin',$p) === NULL) continue; 1216 $menu[] = array('plugin' => $p, 1217 'prompt' => $obj->getMenuText($conf['lang']), 1218 'sort' => $obj->getMenuSort() 1219 ); 1220 } 1221 1222 usort($menu, p_sort_modes); 1223 1224 // output the menu 1225 ptln('<ul>'); 1226 1227 foreach ($menu as $item) { 1228 if (!$item['prompt']) continue; 1229 ptln(' <li><div class="li"><a href="'.wl($ID, 'do=admin&page='.$item['plugin']).'">'.$item['prompt'].'</a></div></li>'); 1230 } 1231 1232 // add in non-plugin functions 1233 if (!$conf['openregister']){ 1234 ptln('<li><div class="li"><a href="'.wl($ID,'do=register').'">'.$lang['admin_register'].'</a></div></li>'); 1235 } 1236 1237 ptln('</ul>'); 1238} 1239 1240/** 1241 * Form to request a new password for an existing account 1242 * 1243 * @author Benoit Chesneau <benoit@bchesneau.info> 1244 */ 1245function html_resendpwd() { 1246 global $lang; 1247 global $conf; 1248 global $ID; 1249 1250 print p_locale_xhtml('resendpwd'); 1251?> 1252 <div class="centeralign"> 1253 <form id="dw__resendpwd" action="<?php echo wl($ID)?>" accept-charset="<?php echo $lang['encoding']?>" method="post"> 1254 <fieldset> 1255 <br /> 1256 <legend><?php echo $lang['resendpwd']?></legend> 1257 <input type="hidden" name="do" value="resendpwd" /> 1258 <input type="hidden" name="save" value="1" /> 1259 <label class="block"> 1260 <span><?php echo $lang['user']?></span> 1261 <input type="text" name="login" value="<?php echo formText($_POST['login'])?>" class="edit" /><br /><br /> 1262 </label><br /> 1263 <input type="submit" value="<?php echo $lang['btn_resendpwd']?>" class="button" /> 1264 </fieldset> 1265 </form> 1266 </div> 1267<?php 1268} 1269 1270//Setup VIM: ex: et ts=2 enc=utf-8 : 1271