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