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