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