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