xref: /dokuwiki/inc/html.php (revision 6b13307fb447795714d01cdc029d6ed7ac087cf3)
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 * @author Andreas Gohr <andi@splitbrain.org>
297 */
298function html_acl($perm){
299  global $INFO;
300  if($INFO['perm'] >= $perm) return true;
301
302  print parsedLocale('denied');
303  return false;
304}
305
306/**
307 * Displays the overall page header and calls html_head()
308 *
309 * @author Andreas Gohr <andi@splitbrain.org>
310 */
311function html_header(){
312  global $ID;
313  global $REV;
314  global $lang;
315  global $conf;
316  html_head();
317?>
318<body>
319  <div class="all">
320  <?
321    @include("includes/topheader.html");
322    html_msgarea();
323  ?>
324  <div class="stylehead">
325    <div class="header">
326      <div class="pagename">
327        [[<a href="<?=wl($ID,'do=backlink')?>" onclick="return svchk()" onkeypress="return svchk()"><?=$ID?></a>]]
328      </div>
329      <div class="logo">
330        <a href="<?=wl()?>" name="top" accesskey="h" title="[ALT+H]" onclick="return svchk()" onkeypress="return svchk()"><?=$conf['title']?></a>
331      </div>
332    </div>
333    <?@include("includes/header.html")?>
334
335    <div class="bar" id="bar_top">
336      <div class="bar-left" id="bar_topleft">
337        <?=html_editbutton()?>
338        <?=html_btn(revs,$ID,'o',array('do' => 'revisions'))?>
339      </div>
340
341      <div class="bar-right" id="bar_topright">
342        <?=html_btn(recent,'','r',array('do' => 'recent'))?>
343        <form action="<?=wl()?>" accept-charset="<?=$lang['encoding']?>">
344          <input type="hidden" name="do" value="search" />
345          <input type="text" accesskey="f" name="id" class="edit" />
346          <input type="submit" value="<?=$lang['btn_search']?>" class="button" />
347        </form>&nbsp;
348      </div>
349    </div>
350
351    <?
352      flush();
353      html_breadcrumbs();
354      @include("includes/pageheader.html");
355    ?>
356  </div>
357  <div class="page">
358  <!-- wikipage start -->
359<?
360}
361
362/**
363 * display document and user info
364 *
365 * Displays some Metadata like who's logged in and the last modified
366 * date - do not confuse this with the HTML meta header.
367 *
368 * @author Andreas Gohr <andi@splitbrain.org>
369 */
370function html_metainfo(){
371  global $conf;
372  global $lang;
373  global $INFO;
374  global $REV;
375
376  $fn = $INFO['filepath'];
377  if(!$conf['fullpath']){
378    if($REV){
379      $fn = str_replace(realpath($conf['olddir']).DIRECTORY_SEPARATOR,'',$fn);
380    }else{
381      $fn = str_replace(realpath($conf['datadir']).DIRECTORY_SEPARATOR,'',$fn);
382    }
383  }
384  $date = date($conf['dformat'],$INFO['lastmod']);
385
386  print '<div class="meta">';
387  if($_SERVER['REMOTE_USER']){
388    print '<div class="user">';
389    print $lang['loggedinas'].': '.$_SERVER['REMOTE_USER'];
390    print '</div>';
391  }
392  print ' &nbsp; ';
393  if($INFO['exists']){
394    print $fn;
395    print ' &middot; ';
396    print $lang['lastmod'];
397    print ': ';
398    print $date;
399    if($INFO['editor']){
400      print ' '.$lang['by'].' ';
401      print $INFO['editor'];
402    }
403    if($INFO['locked']){
404      print ' &middot; ';
405      print $lang['lockedby'];
406      print ': ';
407      print $INFO['locked'];
408    }
409  }
410  print '</div>';
411}
412
413/**
414 * Diplay the overall footer
415 *
416 * @author Andreas Gohr <andi@splitbrain.org>
417 */
418function html_footer(){
419  global $ID;
420  global $REV;
421  global $INFO;
422  global $lang;
423  global $conf;
424?>
425  <!-- wikipage stop -->
426  </div>
427  <div class="clearer">&nbsp;</div>
428  <div class="stylefoot">
429    <?
430      flush();
431      @include("includes/pagefooter.html");
432      html_metainfo();
433    ?>
434    <div class="bar" id="bar_bottom">
435      <div class="bar-left" id="bar_bottomleft">
436        <?=html_editbutton()?>
437        <?=html_btn(revs,$ID,'o',array('do' => 'revisions'))?>
438      </div>
439
440      <div class="bar-right" id="bar_bottomright">
441        <?
442          if($conf['useacl']){
443            if($_SERVER['REMOTE_USER']){
444              print html_btn('logout',$ID,'',array('do' => 'logout',));
445            }else{
446              print html_btn('login',$ID,'',array('do' => 'login'));
447            }
448            #//acl-admin button
449            #if($INFO['perm'] == AUTH_GRANT){
450            #  print html_btn('acl_admin',$ID,'',array('do' => 'acl_admin'));
451            #}
452          }
453        ?>
454        <?=html_btn(index,$ID,'x',array('do' => 'index'))?>
455        <a href="#top"><input type="button" class="button" value="<?=$lang['btn_top']?>" /></a>&nbsp;
456      </div>
457    </div>
458  </div>
459  <?@include("includes/footer.html")?>
460  </div>
461  </body>
462  </html>
463<?
464}
465
466/**
467 * Print the table of contents
468 *
469 * @author Andreas Gohr <andi@splitbrain.org>
470 */
471function html_toc($toc){
472  global $lang;
473  $ret  = '';
474  $ret .= '<div class="toc">';
475  $ret .=   '<div class="tocheader">';
476  $ret .=      $lang['toc'];
477  $ret .=     ' <script type="text/javascript">';
478  $ret .=     'showTocToggle("+","-")';
479  $ret .=     '</script>';
480  $ret .=   '</div>';
481  $ret .=   '<div id="tocinside">';
482  $ret .=   html_buildlist($toc,'toc','html_list_toc');
483  $ret .=   '</div>';
484  $ret .= '</div>';
485  return $ret;
486}
487
488/**
489 * TOC item formatter
490 *
491 * User function for html_buildlist()
492 *
493 * @author Andreas Gohr <andi@splitbrain.org>
494 */
495function html_list_toc($item){
496  $ret  = '';
497  $ret .= '<a href="#'.$item['id'].'" class="toc">';
498  $ret .= $item['name'];
499  $ret .= '</a>';
500  return $ret;
501}
502
503/**
504 * show a wiki page
505 *
506 * @author Andreas Gohr <andi@splitbrain.org>
507 */
508function html_show($text=''){
509  global $ID;
510  global $REV;
511  global $HIGH;
512  //disable section editing for old revisions or in preview
513  if($text || $REV){
514    global $parser;
515    $parser['secedit'] = false;
516  }
517
518  if ($text){
519    //PreviewHeader
520    print parsedLocale('preview');
521    print '<div class="preview">';
522    print html_secedit(parse($text),false);
523    print '</div>';
524  }else{
525    if ($REV) print parsedLocale('showrev');
526    $html = parsedWiki($ID,$REV,true);
527    $html = html_secedit($html);
528    print html_hilight($html,$HIGH);
529  }
530}
531
532/**
533 * Highlights searchqueries in HTML code
534 *
535 * @author Andreas Gohr <andi@splitbrain.org>
536 */
537function html_hilight($html,$query){
538  $queries = preg_split ("/\s/",$query,-1,PREG_SPLIT_NO_EMPTY);
539  foreach ($queries as $q){
540    $q = preg_quote($q,'/');
541    $html = preg_replace("/((<[^>]*)|$q)/ie", '"\2"=="\1"? "\1":"<span class=\"search_hit\">\1</span>"', $html);
542  }
543  return $html;
544}
545
546/**
547 * Run a search and display the result
548 *
549 * @author Andreas Gohr <andi@splitbrain.org>
550 */
551function html_search(){
552  require_once(DOKU_INC.'inc/search.php');
553  global $conf;
554  global $QUERY;
555  global $ID;
556  global $lang;
557
558  print parsedLocale('searchpage');
559  flush();
560
561  //show progressbar
562  print '<div align="center">';
563  print '<script language="JavaScript" type="text/javascript">';
564  print 'showLoadBar();';
565  print '</script>';
566  print '<br /></div>';
567
568  //do quick pagesearch
569  $data = array();
570  search($data,$conf['datadir'],'search_pagename',array(query => cleanID($QUERY)));
571  if(count($data)){
572    sort($data);
573    print '<div class="search_quickresult">';
574    print '<b>'.$lang[quickhits].':</b><br />';
575    foreach($data as $row){
576      print '<div class="search_quickhits">';
577      print html_wikilink(':'.$row['id'],$row['id']);
578      print '</div> ';
579    }
580    //clear float (see http://www.complexspiral.com/publications/containing-floats/)
581    print '<div class="clearer">&nbsp;</div>';
582    print '</div>';
583  }
584  flush();
585
586  //do fulltext search
587  $data = array();
588  search($data,$conf['datadir'],'search_fulltext',array(query => utf8_strtolower($QUERY)));
589  if(count($data)){
590    usort($data,'sort_search_fulltext');
591    foreach($data as $row){
592      print '<div class="search_result">';
593      print html_wikilink(':'.$row['id'],$row['id'],$QUERY);
594      print ': <span class="search_cnt">'.$row['count'].' '.$lang['hits'].'</span><br />';
595      print '<div class="search_snippet">'.$row['snippet'].'</div>';
596      print '</div>';
597    }
598  }else{
599    print '<div align="center">'.$lang['nothingfound'].'</div>';
600  }
601
602  //hide progressbar
603  print '<script language="JavaScript" type="text/javascript">';
604  print 'hideLoadBar();';
605  print '</script>';
606}
607
608/**
609 * Display error on locked pages
610 *
611 * @author Andreas Gohr <andi@splitbrain.org>
612 */
613function html_locked($ip){
614  global $ID;
615  global $conf;
616  global $lang;
617
618  $locktime = filemtime(wikiFN($ID).'.lock');
619  $expire = @date($conf['dformat'], $locktime + $conf['locktime'] );
620  $min    = round(($conf['locktime'] - (time() - $locktime) )/60);
621
622  print parsedLocale('locked');
623  print '<ul>';
624  print '<li><b>'.$lang['lockedby'].':</b> '.$ip.'</li>';
625  print '<li><b>'.$lang['lockexpire'].':</b> '.$expire.' ('.$min.' min)</li>';
626  print '</ul>';
627}
628
629/**
630 * list old revisions
631 *
632 * @author Andreas Gohr <andi@splitbrain.org>
633 */
634function html_revisions(){
635  global $ID;
636  global $INFO;
637  global $conf;
638  global $lang;
639  $revisions = getRevisions($ID);
640  $date = @date($conf['dformat'],$INFO['lastmod']);
641
642  print parsedLocale('revisions');
643  print '<ul>';
644  if($INFO['exists']){
645    print '<li>';
646    print $date.' <a class="wikilink1" href="'.wl($ID).'">'.$ID.'</a> ';
647
648    print $INFO['sum'];
649    print ' <span class="user">(';
650    print $INFO['ip'];
651    if($INFO['user']) print ' '.$INFO['user'];
652    print ')</span> ';
653
654    print '('.$lang['current'].')';
655    print '</li>';
656  }
657
658  foreach($revisions as $rev){
659    $date = date($conf['dformat'],$rev);
660    $info = getRevisionInfo($ID,$rev);
661
662    print '<li>';
663    print $date.' <a class="wikilink1" href="'.wl($ID,"rev=$rev").'">'.$ID.'</a> ';
664    print $info['sum'];
665    print ' <span class="user">(';
666    print $info['ip'];
667    if($info['user']) print ' '.$info['user'];
668    print ')</span> ';
669
670    print '<a href="'.wl($ID,"rev=$rev,do=diff").'">';
671    print '<img src="'.DOKU_BASE.'images/diff.png" border="0" width="15" height="11" title="'.$lang['diff'].'" />';
672    print '</a>';
673    print '</li>';
674  }
675  print '</ul>';
676}
677
678/**
679 * display recent changes
680 *
681 * @author Andreas Gohr <andi@splitbrain.org>
682 */
683function html_recent(){
684  global $conf;
685  $recents = getRecents(0,true);
686
687  print parsedLocale('recent');
688  print '<ul>';
689  foreach(array_keys($recents) as $id){
690    $date = date($conf['dformat'],$recents[$id]['date']);
691    print '<li>';
692    print $date.' '.html_wikilink($id,$id);
693    print ' '.htmlspecialchars($recents[$id]['sum']);
694    print ' <span class="user">(';
695    print $recents[$id]['ip'];
696    if($recents[$id]['user']) print ' '.$recents[$id]['user'];
697    print ')</span>';
698    print '</li>';
699  }
700  print '</ul>';
701}
702
703/**
704 * Display page index
705 *
706 * @author Andreas Gohr <andi@splitbrain.org>
707 */
708function html_index($ns){
709  require_once(DOKU_INC.'inc/search.php');
710  global $conf;
711  global $ID;
712  $dir = $conf['datadir'];
713  $ns  = cleanID($ns);
714  if(empty($ns)){
715    $ns = dirname(str_replace(':','/',$ID));
716    if($ns == '.') $ns ='';
717  }
718  $ns  = utf8_encodeFN(str_replace(':','/',$ns));
719
720  print parsedLocale('index');
721
722  $data = array();
723  search($data,$conf['datadir'],'search_index',array('ns' => $ns));
724  print html_buildlist($data,'idx','html_list_index','html_li_index');
725}
726
727/**
728 * Index item formatter
729 *
730 * User function for html_buildlist()
731 *
732 * @author Andreas Gohr <andi@splitbrain.org>
733 */
734function html_list_index($item){
735  $ret = '';
736  $base = ':'.$item['id'];
737  $base = substr($base,strrpos($base,':')+1);
738  if($item['type']=='d'){
739    $ret .= '<a href="'.wl($ID,'idx='.$item['id']).'" class="idx_dir">';
740    $ret .= $base;
741    $ret .= '</a>';
742  }else{
743    $ret .= html_wikilink(':'.$item['id']);
744  }
745  return $ret;
746}
747
748/**
749 * Index List item
750 *
751 * This user function is used in html_build_lidt to build the
752 * <li> tags for namespaces when displaying the page index
753 * it gives different classes to opened or closed "folders"
754 *
755 * @author Andreas Gohr <andi@splitbrain.org>
756 */
757function html_li_index($item){
758  if($item['type'] == "f"){
759    return '<li class="level'.$item['level'].'">';
760  }elseif($item['open']){
761    return '<li class="open">';
762  }else{
763    return '<li class="closed">';
764  }
765}
766
767/**
768 * Default List item
769 *
770 * @author Andreas Gohr <andi@splitbrain.org>
771 */
772function html_li_default($item){
773  return '<li class="level'.$item['level'].'">';
774}
775
776/**
777 * Build an unordered list
778 *
779 * Build an unordered list from the given $data array
780 * Each item in the array has to have a 'level' property
781 * the item itself gets printed by the given $func user
782 * function. The second and optional function is used to
783 * print the <li> tag. Both user function need to accept
784 * a single item.
785 *
786 * @author Andreas Gohr <andi@splitbrain.org>
787 */
788function html_buildlist($data,$class,$func,$lifunc='html_li_default'){
789  $level = 0;
790  $opens = 0;
791  $ret   = '';
792
793  foreach ($data as $item){
794
795    if( $item['level'] > $level ){
796      //open new list
797      for($i=0; $i<($item['level'] - $level); $i++){
798        if ($i) $ret .= "<li class=\"clear\">\n";
799        $ret .= "\n<ul class=\"$class\">\n";
800      }
801    }elseif( $item['level'] < $level ){
802      //close last item
803      $ret .= "</li>\n";
804      for ($i=0; $i<($level - $item['level']); $i++){
805        //close higher lists
806        $ret .= "</ul>\n</li>\n";
807      }
808    }else{
809      //close last item
810      $ret .= "</li>\n";
811    }
812
813    //remember current level
814    $level = $item['level'];
815
816    //print item
817    $ret .= $lifunc($item); //user function
818    $ret .= '<span class="li">';
819    $ret .= $func($item); //user function
820    $ret .= '</span>';
821  }
822
823  //close remaining items and lists
824  for ($i=0; $i < $level; $i++){
825    $ret .= "</li></ul>\n";
826  }
827
828  return $ret;
829}
830
831/**
832 * display backlinks
833 *
834 * @author Andreas Gohr <andi@splitbrain.org>
835 */
836function html_backlinks(){
837  require_once(DOKU_INC.'inc/search.php');
838  global $ID;
839  global $conf;
840
841  if(preg_match('#^(.*):(.*)$#',$ID,$matches)){
842    $opts['ns']   = $matches[1];
843    $opts['name'] = $matches[2];
844  }else{
845    $opts['ns']   = '';
846    $opts['name'] = $ID;
847  }
848
849  print parsedLocale('backlinks');
850
851  $data = array();
852  search($data,$conf['datadir'],'search_backlinks',$opts);
853  sort($data);
854
855  print '<ul class="idx">';
856  foreach($data as $row){
857    print '<li>';
858    print html_wikilink(':'.$row['id'],$row['id']);
859    print '</li>';
860  }
861  print '</ul>';
862}
863
864/**
865 * show diff
866 *
867 * @author Andreas Gohr <andi@splitbrain.org>
868 */
869function html_diff($text='',$intro=true){
870  require_once(DOKU_INC.'inc/DifferenceEngine.php');
871  global $ID;
872  global $REV;
873  global $lang;
874  global $conf;
875  if($text){
876    $df  = new Diff(split("\n",htmlspecialchars(rawWiki($ID,''))),
877                    split("\n",htmlspecialchars(cleanText($text))));
878    $left  = '<a class="wikilink1" href="'.wl($ID).'">'.
879              $ID.' '.date($conf['dformat'],@filemtime(wikiFN($ID))).'</a>'.
880              $lang['current'];
881    $right = $lang['yours'];
882  }else{
883    $df  = new Diff(split("\n",htmlspecialchars(rawWiki($ID,$REV))),
884                    split("\n",htmlspecialchars(rawWiki($ID,''))));
885    $left  = '<a class="wikilink1" href="'.wl($ID,"rev=$REV").'">'.
886              $ID.' '.date($conf['dformat'],$REV).'</a>';
887    $right = '<a class="wikilink1" href="'.wl($ID).'">'.
888              $ID.' '.date($conf['dformat'],@filemtime(wikiFN($ID))).'</a> '.
889              $lang['current'];
890  }
891  $tdf = new TableDiffFormatter();
892  if($intro) print parsedLocale('diff');
893  ?>
894    <table class="diff" width="100%">
895      <tr>
896        <td colspan="2" width="50%" class="diff-header">
897          <?=$left?>
898        </td>
899        <td colspan="2" width="50%" class="diff-header">
900          <?=$right?>
901        </td>
902      </tr>
903      <?=$tdf->format($df)?>
904    </table>
905  <?
906}
907
908/**
909 * show warning on conflict detection
910 *
911 * @author Andreas Gohr <andi@splitbrain.org>
912 */
913function html_conflict($text,$summary){
914  global $ID;
915  global $lang;
916
917  print parsedLocale('conflict');
918  ?>
919  <form name="editform" method="post" action="<?=script()?>" accept-charset="<?=$lang['encoding']?>">
920  <input type="hidden" name="id" value="<?=$ID?>" />
921  <input type="hidden" name="wikitext" value="<?=formText($text)?>" />
922  <input type="hidden" name="summary" value="<?=formText($summary)?>" />
923
924  <div align="center">
925    <input class="button" type="submit" name="do" value="<?=$lang['btn_save']?>" accesskey="s" title="[ALT+S]" />
926    <input class="button" type="submit" name="do" value="<?=$lang['btn_cancel']?>" />
927  </div>
928  </form>
929  <br /><br /><br /><br />
930  <?
931}
932
933/**
934 * Prints the global message array
935 *
936 * @author Andreas Gohr <andi@splitbrain.org>
937 */
938function html_msgarea(){
939  global $MSG;
940
941  if(!isset($MSG)) return;
942
943  foreach($MSG as $msg){
944    print '<div class="'.$msg['lvl'].'">';
945    print $msg['msg'];
946    print '</div>';
947  }
948}
949
950/**
951 * Prints the registration form
952 *
953 * @author Andreas Gohr <andi@splitbrain.org>
954 */
955function html_register(){
956  global $lang;
957  global $ID;
958
959  print parsedLocale('register');
960?>
961  <div align="center">
962  <form name="register" method="post" action="<?=wl($ID)?>" accept-charset="<?=$lang['encoding']?>">
963  <input type="hidden" name="do" value="register" />
964  <input type="hidden" name="save" value="1" />
965  <fieldset>
966    <legend><?=$lang['register']?></legend>
967    <label>
968      <?=$lang['user']?>
969      <input type="text" name="login" class="edit" size="50" value="<?=formText($_POST['login'])?>" />
970    </label><br />
971    <label>
972      <?=$lang['fullname']?>
973      <input type="text" name="fullname" class="edit" size="50" value="<?=formText($_POST['fullname'])?>" />
974    </label><br />
975    <label>
976      <?=$lang['email']?>
977      <input type="text" name="email" class="edit" size="50" value="<?=formText($_POST['email'])?>" />
978    </label><br />
979    <input type="submit" class="button" value="<?=$lang['register']?>" />
980  </fieldset>
981  </form>
982  </div>
983<?
984}
985
986/**
987 * This displays the edit form (lots of logic included)
988 *
989 * @author Andreas Gohr <andi@splitbrain.org>
990 */
991function html_edit($text=null,$include='edit'){ //FIXME: include needed?
992  global $ID;
993  global $REV;
994  global $DATE;
995  global $RANGE;
996  global $PRE;
997  global $SUF;
998  global $INFO;
999  global $SUM;
1000  global $lang;
1001  global $conf;
1002
1003  //check for create permissions first
1004  if(!$INFO['exists'] && !html_acl(AUTH_CREATE)) return;
1005
1006  //set summary default
1007  if(!$SUM){
1008    if($REV){
1009      $SUM = $lang['restored'];
1010    }elseif(!$INFO['exists']){
1011      $SUM = $lang['created'];
1012    }
1013  }
1014
1015  //no text? Load it!
1016  if(!isset($text)){
1017    $pr = false; //no preview mode
1018    if($RANGE){
1019      list($PRE,$text,$SUF) = rawWikiSlices($RANGE,$ID,$REV);
1020    }else{
1021      $text = rawWiki($ID,$REV);
1022    }
1023  }else{
1024    $pr = true; //preview mode
1025  }
1026
1027  $wr = $INFO['writable'];
1028  if($wr){
1029    if ($REV) print parsedLocale('editrev');
1030    print parsedLocale($include);
1031  }else{
1032    print parsedLocale('read');
1033    $ro='readonly="readonly"';
1034  }
1035  if(!$DATE) $DATE = $INFO['lastmod'];
1036?>
1037  <form name="editform" method="post" action="<?=script()?>" accept-charset="<?=$lang['encoding']?>" onsubmit="return svchk()">
1038  <input type="hidden" name="id"   value="<?=$ID?>" />
1039  <input type="hidden" name="rev"  value="<?=$REV?>" />
1040  <input type="hidden" name="date" value="<?=$DATE?>" />
1041  <input type="hidden" name="prefix" value="<?=formText($PRE)?>" />
1042  <input type="hidden" name="suffix" value="<?=formText($SUF)?>" />
1043  <table style="width:99%">
1044    <tr>
1045      <td class="toolbar" colspan="3">
1046        <?if($wr){?>
1047        <script language="JavaScript" type="text/javascript">
1048          <?/* sets changed to true when previewed */?>
1049          textChanged = <? ($pr) ? print 'true' : print 'false' ?>;
1050
1051          formatButton('images/bold.png','<?=$lang['qb_bold']?>','**','**','<?=$lang['qb_bold']?>','b');
1052          formatButton('images/italic.png','<?=$lang['qb_italic']?>',"\/\/","\/\/",'<?=$lang['qb_italic']?>','i');
1053          formatButton('images/underline.png','<?=$lang['qb_underl']?>','__','__','<?=$lang['qb_underl']?>','u');
1054          formatButton('images/code.png','<?=$lang['qb_code']?>','\'\'','\'\'','<?=$lang['qb_code']?>','c');
1055
1056          formatButton('images/fonth1.png','<?=$lang['qb_h1']?>','====== ',' ======\n','<?=$lang['qb_h1']?>','1');
1057          formatButton('images/fonth2.png','<?=$lang['qb_h2']?>','===== ',' =====\n','<?=$lang['qb_h2']?>','2');
1058          formatButton('images/fonth3.png','<?=$lang['qb_h3']?>','==== ',' ====\n','<?=$lang['qb_h3']?>','3');
1059          formatButton('images/fonth4.png','<?=$lang['qb_h4']?>','=== ',' ===\n','<?=$lang['qb_h4']?>','4');
1060          formatButton('images/fonth5.png','<?=$lang['qb_h5']?>','== ',' ==\n','<?=$lang['qb_h5']?>','5');
1061
1062          formatButton('images/link.png','<?=$lang['qb_link']?>','[[',']]','<?=$lang['qb_link']?>','l');
1063          formatButton('images/extlink.png','<?=$lang['qb_extlink']?>','[[',']]','http://www.example.com|<?=$lang['qb_extlink']?>');
1064
1065          formatButton('images/list.png','<?=$lang['qb_ol']?>','  - ','\n','<?=$lang['qb_ol']?>');
1066          formatButton('images/list_ul.png','<?=$lang['qb_ul']?>','  * ','\n','<?=$lang['qb_ul']?>');
1067
1068          insertButton('images/rule.png','<?=$lang['qb_hr']?>','----\n');
1069          mediaButton('images/image.png','<?=$lang['qb_media']?>','m','<?=$INFO['namespace']?>');
1070
1071          <?
1072          if($conf['useacl'] && $_SERVER['REMOTE_USER']){
1073            echo "insertButton('images/sig.png','".$lang['qb_sig']."','".html_signature()."','y');";
1074          }
1075          ?>
1076        </script>
1077        <?}?>
1078      </td>
1079    </tr>
1080    <tr>
1081      <td colspan="3">
1082        <textarea name="wikitext" id="wikitext" <?=$ro?> cols="80" rows="10" class="edit" onchange="textChanged = true;" onkeyup="summaryCheck();" tabindex="1"><?="\n".formText($text)?></textarea>
1083      </td>
1084    </tr>
1085    <tr>
1086      <td>
1087      <?if($wr){?>
1088        <input class="button" type="submit" name="do" value="<?=$lang['btn_save']?>" accesskey="s" title="[ALT+S]" onclick="textChanged=false" onkeypress="textChanged=false" tabindex="3" />
1089        <input class="button" type="submit" name="do" value="<?=$lang['btn_preview']?>" accesskey="p" title="[ALT+P]" onclick="textChanged=false" onkeypress="textChanged=false" tabindex="4" />
1090        <input class="button" type="submit" name="do" value="<?=$lang['btn_cancel']?>" tabindex="5" />
1091      <?}?>
1092      </td>
1093      <td>
1094      <?if($wr){?>
1095        <?=$lang['summary']?>:
1096        <input type="text" class="edit" name="summary" id="summary" size="50" onkeyup="summaryCheck();" value="<?=formText($SUM)?>" tabindex="2" />
1097      <?}?>
1098      </td>
1099      <td align="right">
1100        <script type="text/javascript">
1101          showSizeCtl();
1102          <?if($wr){?>
1103            init_locktimer(<?=$conf['locktime']-60?>,'<?=$lang['willexpire']?>');
1104            document.editform.wikitext.focus();
1105          <?}?>
1106        </script>
1107      </td>
1108    </tr>
1109  </table>
1110  </form>
1111<?
1112}
1113
1114/**
1115 * prepares the signature string as configured in the config
1116 *
1117 * @author Andreas Gohr <andi@splitbrain.org>
1118 */
1119function html_signature(){
1120  global $conf;
1121  global $INFO;
1122
1123  $sig = $conf['signature'];
1124  $sig = strftime($sig);
1125  $sig = str_replace('@USER@',$_SERVER['REMOTE_USER'],$sig);
1126  $sig = str_replace('@NAME@',$INFO['userinfo']['name'],$sig);
1127  $sig = str_replace('@MAIL@',$INFO['userinfo']['mail'],$sig);
1128  $sig = str_replace('@DATE@',date($conf['dformat']),$sig);
1129  return $sig;
1130}
1131
1132/**
1133 * prints some debug info
1134 *
1135 * @author Andreas Gohr <andi@splitbrain.org>
1136 */
1137function html_debug(){
1138  global $conf;
1139  global $lang;
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  print '<b>Environment:</b><pre>';
1185  print_r($_ENV);
1186  print '</pre>';
1187
1188  print '<b>PHP settings:</b><pre>';
1189  $inis = ini_get_all();
1190  print_r($inis);
1191  print '</pre>';
1192
1193  print '</body></html>';
1194}
1195
1196/**
1197 * prints the acl-admin form(s)
1198 *
1199 * @author Frank Schubert <frank@schokilade.de>
1200 */
1201function html_acl_admin(){
1202  global $lang;
1203  global $ID;
1204  global $INFO;
1205
1206  print parsedLocale('acl_admin');
1207?>
1208  <fieldset style="float:left; text-align:left; white-space:nowrap; width:320px;">
1209    <legend><?=$lang['acl_admin']?></legend>
1210
1211    <form name="acl_admin_add" method="post" action="<?=wl($ID)?>" accept-charset="<?=$lang['encoding']?>">
1212      <input type="hidden" name="do" value="acl_admin_add" />
1213      <input type="hidden" name="save" value="1" />
1214      <table>
1215        <tr>
1216    <td><?=$lang['acl_user']?></td>
1217    <td><input type="text" name="acl_user" class="edit" size="20" value="" /></td>
1218    </tr><tr>
1219        <td><?=$lang['acl_scope']?></td>
1220    <td><select name="acl_scope" id="acl_scope" class="edit" size="1" onChange="checkAclLevel();">
1221        <option value="">(<?=$lang['acl_input_request']?>)</option>
1222        <option><?=$ID?></option>
1223        <?php if( ($ns=getNS($ID)) != NULL) {?>
1224                 <option><?=$ns?>:*</option>
1225        <?php }else{ ?>
1226                 <option>*</option>
1227        <?php } ?>
1228        </select></td>
1229    </tr><tr>
1230        <td style="vertical-align:top"><?=$lang['acl_level']?></td>
1231        <td>
1232      <input type="checkbox" name="acl_checkbox[1]" value="on" checked="checked" /><?=$lang['acl_read']?><br />
1233      <input type="checkbox" name="acl_checkbox[2]" value="on" /><?=$lang['acl_edit']?><br />
1234      <input type="checkbox" name="acl_checkbox[4]" value="on" /><?=$lang['acl_create']?><br />
1235      <input type="checkbox" name="acl_checkbox[8]" value="on" /><?=$lang['acl_upload']?>
1236    </td>
1237    </tr><tr>
1238    <td></td>
1239    <td><input type="submit" class="button" value="<?=$lang['acl_commit']?>" /></td>
1240        </tr>
1241      </table>
1242    </form>
1243  </fieldset>
1244
1245  <div style="float:right;">
1246    <fieldset>
1247    <legend><?=$lang['acl_current']?></legend>
1248    <div style="text-align:left">
1249    <?php
1250      $acl_config=get_acl_config($ID);
1251      foreach($acl_config as $pagename => $value){
1252        if($pagename != '*') {
1253      $ID_cur=$pagename;
1254          while(($piece=getNS($ID_cur)) !== false){
1255            $url="<a href='".wl($piece,'do=acl_admin')."'>".noNS($piece)."</a>:".$url;;
1256            $ID_cur=$piece;
1257          }
1258          $url.="<a href='".wl($pagename,'do=acl_admin')."'>".noNS($pagename)."</a>";
1259          print $url;
1260          $url='';
1261           }else{
1262             print $pagename;
1263           } ?>
1264           <table class="inline">
1265             <tr>
1266               <th class="inline"></th>
1267               <th class="inline">name</th>
1268               <th class="inline">R</th>
1269               <th class="inline">W</th>
1270               <th class="inline">C</th>
1271               <th class="inline">U</th>
1272        <th class="inline">UPDATE</th>
1273               <th class="inline">DELETE</th>
1274             </tr>
1275           <?php
1276           foreach($value as $conf){
1277           ?>
1278             <tr>
1279        <!-- user/group -->
1280            <td class="inline">
1281              <?php
1282    	$group = false;
1283            if(substr($conf[0],0,1)=="@"){
1284    	  print $lang['acl_group'];
1285    	  $group = true;
1286    	}else{
1287    	  print $lang['acl_user'];
1288    	}
1289              ?>
1290            </td>
1291        <td class="inline">
1292        <!-- name -->
1293          <?php
1294    	if($group) { print substr($conf[0],1); } else { print $conf[0]; }
1295          ?>
1296        </td>
1297        <form name="acl_admin_change" method="post" action="<?=wl($ID)?>" accept-charset="<?=$lang['encoding']?>">
1298        <?php
1299          // read,write,create,upload
1300          $acl_nums=array(1,2,4,8);
1301          foreach($acl_nums as $num){
1302    	?><td class="inline">
1303    	  <input type="hidden" name="do" value="acl_admin_change" />
1304                  <input type="hidden" name="save" value="1" />
1305    	  <input type="hidden" name="acl_scope" value='<?=urlencode($pagename)?>' />
1306    	  <input type="hidden" name="acl_user" value='<?=urlencode($conf[0])?>' />
1307    	  <input type="hidden" name="acl_level" value='<?=$conf[1]?>' />
1308    	  <input type="checkbox" name="acl_checkbox[<?=$num?>]" value="on"<?php
1309    	  if($conf[1]>=$num) {
1310    	  ?> checked="checked"<?php
1311    	  }
1312    	?> /></td><?php
1313          }
1314        ?>
1315        <td class="inline"><input type="submit" class="button" value="update"></td>
1316        </form>
1317            <td class="inline">
1318        <!-- delete form -->
1319            <form name="acl_admin_del" method="post" action="<?=wl($ID)?>" accept-charset="<?=$lang['encoding']?>">
1320              <input type="hidden" name="do" value="acl_admin_del" />
1321              <input type="hidden" name="save" value="1" />
1322              <input type="hidden" name="acl_scope" value='<?=urlencode($pagename);?>' />
1323             <input type="hidden" name="acl_user" value='<?=urlencode($conf[0])?>' />
1324          <input type="hidden" name="acl_level" value='<?=$conf[1]?>' />
1325              <input type="submit" class="button" value='DEL' onClick="return window.confirm('<?=$lang['acl_confirm_delete']?>');" />
1326            </form>
1327            </td>
1328             </tr>
1329           <?php
1330           }
1331      ?></table><?php
1332      }
1333    ?>
1334    </div>
1335    </fieldset>
1336  </div>
1337<?
1338}
1339?>
1340