xref: /dokuwiki/inc/html.php (revision 35dae8b08b9fb243b06bc972c20a0b00a8d97f0b)
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">&nbsp;</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&amp;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