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