xref: /dokuwiki/inc/html.php (revision 92a40cd9c6ed174a2d59eaaf8d18f4a18580d146)
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
9if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../').'/');
10if(!defined('NL')) define('NL',"\n");
11require_once(DOKU_INC.'inc/parserutils.php');
12require_once(DOKU_INC.'inc/form.php');
13
14/**
15 * Convenience function to quickly build a wikilink
16 *
17 * @author Andreas Gohr <andi@splitbrain.org>
18 */
19function html_wikilink($id,$name=NULL,$search=''){
20  static $xhtml_renderer = NULL;
21  if(is_null($xhtml_renderer)){
22    require_once(DOKU_INC.'inc/parser/xhtml.php');
23    $xhtml_renderer = new Doku_Renderer_xhtml();
24  }
25
26  return $xhtml_renderer->internallink($id,$name,$search,true);
27}
28
29/**
30 * Helps building long attribute lists
31 *
32 * @author Andreas Gohr <andi@splitbrain.org>
33 */
34function html_attbuild($attributes){
35  $ret = '';
36  foreach ( $attributes as $key => $value ) {
37    $ret .= $key.'="'.formtext($value).'" ';
38  }
39  return trim($ret);
40}
41
42/**
43 * The loginform
44 *
45 * @author   Andreas Gohr <andi@splitbrain.org>
46 */
47function html_login(){
48  global $lang;
49  global $conf;
50  global $ID;
51  global $auth;
52
53  print p_locale_xhtml('login');
54  print '<div class="centeralign">'.NL;
55  $form = new Doku_Form('dw__login');
56  $form->startFieldset($lang['btn_login']);
57  $form->addHidden('id', $ID);
58  $form->addHidden('do', 'login');
59  $form->addElement(form_makeTextField('u', ((!$_REQUEST['http_credentials']) ? $_REQUEST['u'] : ''), $lang['user'], 'focus__this', 'block'));
60  $form->addElement(form_makePasswordField('p', $lang['pass'], '', 'block'));
61  if($conf['rememberme']) {
62      $form->addElement(form_makeCheckboxField('r', '1', $lang['remember'], 'remember__me', 'simple'));
63  }
64  $form->addElement(form_makeButton('submit', '', $lang['btn_login']));
65  $form->endFieldset();
66  html_form('login', $form);
67
68  if($auth && $auth->canDo('addUser') && actionOK('register')){
69    print '<p>';
70    print $lang['reghere'];
71    print ': <a href="'.wl($ID,'do=register').'" rel="nofollow" class="wikilink1">'.$lang['register'].'</a>';
72    print '</p>';
73  }
74
75  if ($auth && $auth->canDo('modPass') && actionOK('resendpwd')) {
76    print '<p>';
77    print $lang['pwdforget'];
78    print ': <a href="'.wl($ID,'do=resendpwd').'" rel="nofollow" class="wikilink1">'.$lang['btn_resendpwd'].'</a>';
79    print '</p>';
80  }
81  print '</div>'.NL;
82}
83
84/**
85 * prints a section editing button
86 * used as a callback in html_secedit
87 *
88 * @author Andreas Gohr <andi@splitbrain.org>
89 */
90function html_secedit_button($matches){
91  global $ID;
92  global $INFO;
93
94  $section = $matches[2];
95  $name = $matches[1];
96
97  $secedit  = '';
98  $secedit .= '<div class="secedit">';
99  $secedit .= html_btn('secedit',$ID,'',
100                        array('do'      => 'edit',
101                              'lines'   => "$section",
102                              'rev' => $INFO['lastmod']),
103                              'post', $name);
104  $secedit .= '</div>';
105  return $secedit;
106}
107
108/**
109 * inserts section edit buttons if wanted or removes the markers
110 *
111 * @author Andreas Gohr <andi@splitbrain.org>
112 */
113function html_secedit($text,$show=true){
114  global $INFO;
115
116  if($INFO['writable'] && $show && !$INFO['rev']){
117    $text = preg_replace_callback('#<!-- SECTION "(.*?)" \[(\d+-\d*)\] -->#',
118                         'html_secedit_button', $text);
119  }else{
120    $text = preg_replace('#<!-- SECTION "(.*?)" \[(\d+-\d*)\] -->#','',$text);
121  }
122
123  return $text;
124}
125
126/**
127 * Just the back to top button (in its own form)
128 *
129 * @author Andreas Gohr <andi@splitbrain.org>
130 */
131function html_topbtn(){
132  global $lang;
133
134  $ret  = '';
135  $ret  = '<a class="nolink" href="#dokuwiki__top"><input type="button" class="button" value="'.$lang['btn_top'].'" onclick="window.scrollTo(0, 0)" title="'.$lang['btn_top'].'" /></a>';
136
137  return $ret;
138}
139
140/**
141 * Displays a button (using its own form)
142 * If tooltip exists, the access key tooltip is replaced.
143 *
144 * @author Andreas Gohr <andi@splitbrain.org>
145 */
146function html_btn($name,$id,$akey,$params,$method='get',$tooltip=''){
147  global $conf;
148  global $lang;
149
150  $label = $lang['btn_'.$name];
151
152  $ret = '';
153  $tip = '';
154
155  //filter id (without urlencoding)
156  $id = idfilter($id,false);
157
158  //make nice URLs even for buttons
159  if($conf['userewrite'] == 2){
160    $script = DOKU_BASE.DOKU_SCRIPT.'/'.$id;
161  }elseif($conf['userewrite']){
162    $script = DOKU_BASE.$id;
163  }else{
164    $script = DOKU_BASE.DOKU_SCRIPT;
165    $params['id'] = $id;
166  }
167
168  $ret .= '<form class="button btn_'.$name.'" method="'.$method.'" action="'.$script.'"><div class="no">';
169
170  if(is_array($params)){
171    reset($params);
172    while (list($key, $val) = each($params)) {
173      $ret .= '<input type="hidden" name="'.$key.'" ';
174      $ret .= 'value="'.htmlspecialchars($val).'" />';
175    }
176  }
177
178  if ($tooltip!='') {
179      $tip = htmlspecialchars($tooltip);
180  }else{
181      $tip = htmlspecialchars($label);
182  }
183
184  $ret .= '<input type="submit" value="'.htmlspecialchars($label).'" class="button" ';
185  if($akey){
186    $tip .= ' ['.strtoupper($akey).']';
187    $ret .= 'accesskey="'.htmlspecialchars($label).' '.$akey.'" ';
188  }
189  $ret .= 'title="'.$tip.'" ';
190  $ret .= '/>';
191  $ret .= '</div></form>';
192
193  return $ret;
194}
195
196/**
197 * show a wiki page
198 *
199 * @author Andreas Gohr <andi@splitbrain.org>
200 */
201function html_show($txt=''){
202  global $ID;
203  global $REV;
204  global $HIGH;
205  global $INFO;
206  //disable section editing for old revisions or in preview
207  if($txt || $REV){
208    $secedit = false;
209  }else{
210    $secedit = true;
211  }
212
213  if ($txt){
214    //PreviewHeader
215    echo '<br id="scroll__here" />';
216    echo p_locale_xhtml('preview');
217    echo '<div class="preview">';
218    $html = html_secedit(p_render('xhtml',p_get_instructions($txt),$info),$secedit);
219    if($INFO['prependTOC']) $html = tpl_toc(true).$html;
220    echo $html;
221    echo '<div class="clearer"></div>';
222    echo '</div>';
223
224  }else{
225    if ($REV) print p_locale_xhtml('showrev');
226    $html = p_wiki_xhtml($ID,$REV,true);
227    $html = html_secedit($html,$secedit);
228    if($INFO['prependTOC']) $html = tpl_toc(true).$html;
229    $html = html_hilight($html,$HIGH);
230    echo $html;
231  }
232}
233
234/**
235 * ask the user about how to handle an exisiting draft
236 *
237 * @author Andreas Gohr <andi@splitbrain.org>
238 */
239function html_draft(){
240  global $INFO;
241  global $ID;
242  global $lang;
243  global $conf;
244  $draft = unserialize(io_readFile($INFO['draft'],false));
245  $text  = cleanText(con($draft['prefix'],$draft['text'],$draft['suffix'],true));
246
247  print p_locale_xhtml('draft');
248  $form = new Doku_Form('dw__editform');
249  $form->addHidden('id', $ID);
250  $form->addHidden('date', $draft['date']);
251  $form->addElement(form_makeWikiText($text, array('readonly'=>'readonly')));
252  $form->addElement(form_makeOpenTag('div', array('id'=>'draft__status')));
253  $form->addElement($lang['draftdate'].' '. strftime($conf['dformat'],filemtime($INFO['draft'])));
254  $form->addElement(form_makeCloseTag('div'));
255  $form->addElement(form_makeButton('submit', 'recover', $lang['btn_recover'], array('tabindex'=>'1')));
256  $form->addElement(form_makeButton('submit', 'draftdel', $lang['btn_draftdel'], array('tabindex'=>'2')));
257  $form->addElement(form_makeButton('submit', 'show', $lang['btn_cancel'], array('tabindex'=>'3')));
258  html_form('draft', $form);
259}
260
261/**
262 * Highlights searchqueries in HTML code
263 *
264 * @author Andreas Gohr <andi@splitbrain.org>
265 * @author Harry Fuecks <hfuecks@gmail.com>
266 */
267function html_hilight($html,$phrases){
268  $regex = join('|',array_map('preg_quote_cb',array_filter((array) $phrases)));
269
270  if ($regex === '') return $html;
271  $html = preg_replace_callback("/((<[^>]*)|$regex)/ui",'html_hilight_callback',$html);
272  return $html;
273}
274
275/**
276 * Callback used by html_hilight()
277 *
278 * @author Harry Fuecks <hfuecks@gmail.com>
279 */
280function html_hilight_callback($m) {
281  $hlight = unslash($m[0]);
282  if ( !isset($m[2])) {
283    $hlight = '<span class="search_hit">'.$hlight.'</span>';
284  }
285  return $hlight;
286}
287
288/**
289 * Run a search and display the result
290 *
291 * @author Andreas Gohr <andi@splitbrain.org>
292 */
293function html_search(){
294  require_once(DOKU_INC.'inc/search.php');
295  require_once(DOKU_INC.'inc/fulltext.php');
296  global $conf;
297  global $QUERY;
298  global $ID;
299  global $lang;
300
301  print p_locale_xhtml('searchpage');
302  flush();
303
304  //check if search is restricted to namespace
305  if(preg_match('/([^@]*)@([^@]*)/',$QUERY,$match)) {
306      $id = cleanID($match[1]);
307      if(empty($id)) {
308        print '<div class="nothing">'.$lang['nothingfound'].'</div>';
309        flush();
310        return;
311      }
312  } else {
313      $id = cleanID($QUERY);
314  }
315
316  //show progressbar
317  print '<div class="centeralign" id="dw__loading">'.NL;
318  print '<script type="text/javascript" charset="utf-8"><!--//--><![CDATA[//><!--'.NL;
319  print 'showLoadBar();'.NL;
320  print '//--><!]]></script>'.NL;
321  print '<br /></div>'.NL;
322  flush();
323
324  //do quick pagesearch
325  $data = array();
326
327  $data = ft_pageLookup($id);
328  if(count($data)){
329    print '<div class="search_quickresult">';
330    print '<h3>'.$lang['quickhits'].':</h3>';
331    print '<ul class="search_quickhits">';
332    foreach($data as $id){
333      print '<li> ';
334      $ns = getNS($id);
335      if($ns){
336        $name = shorten(noNS($id), ' ('.$ns.')',30);
337      }else{
338        $name = $id;
339      }
340      print html_wikilink(':'.$id,$name);
341      print '</li> ';
342    }
343    print '</ul> ';
344    //clear float (see http://www.complexspiral.com/publications/containing-floats/)
345    print '<div class="clearer">&nbsp;</div>';
346    print '</div>';
347  }
348  flush();
349
350  //do fulltext search
351  $data = ft_pageSearch($QUERY,$regex);
352  if(count($data)){
353    $num = 1;
354    foreach($data as $id => $cnt){
355      print '<div class="search_result">';
356      print html_wikilink(':'.$id,$conf['useheading']?NULL:$id,$regex);
357      print ': <span class="search_cnt">'.$cnt.' '.$lang['hits'].'</span><br />';
358      if($num < 15){ // create snippets for the first number of matches only #FIXME add to conf ?
359        print '<div class="search_snippet">'.ft_snippet($id,$regex).'</div>';
360      }
361      print '</div>';
362      flush();
363      $num++;
364    }
365  }else{
366    print '<div class="nothing">'.$lang['nothingfound'].'</div>';
367  }
368
369  //hide progressbar
370  print '<script type="text/javascript" charset="utf-8"><!--//--><![CDATA[//><!--'.NL;
371  print 'hideLoadBar("dw__loading");'.NL;
372  print '//--><!]]></script>'.NL;
373  flush();
374}
375
376/**
377 * Display error on locked pages
378 *
379 * @author Andreas Gohr <andi@splitbrain.org>
380 */
381function html_locked(){
382  global $ID;
383  global $conf;
384  global $lang;
385  global $INFO;
386
387  $locktime = filemtime(wikiLockFN($ID));
388  $expire = @strftime($conf['dformat'], $locktime + $conf['locktime'] );
389  $min    = round(($conf['locktime'] - (time() - $locktime) )/60);
390
391  print p_locale_xhtml('locked');
392  print '<ul>';
393  print '<li><div class="li"><strong>'.$lang['lockedby'].':</strong> '.$INFO['locked'].'</div></li>';
394  print '<li><div class="li"><strong>'.$lang['lockexpire'].':</strong> '.$expire.' ('.$min.' min)</div></li>';
395  print '</ul>';
396}
397
398/**
399 * list old revisions
400 *
401 * @author Andreas Gohr <andi@splitbrain.org>
402 * @author Ben Coburn <btcoburn@silicodon.net>
403 */
404function html_revisions($first=0){
405  global $ID;
406  global $INFO;
407  global $conf;
408  global $lang;
409  /* we need to get one additionally log entry to be able to
410   * decide if this is the last page or is there another one.
411   * see html_recent()
412   */
413  $revisions = getRevisions($ID, $first, $conf['recent']+1);
414  if(count($revisions)==0 && $first!=0){
415    $first=0;
416    $revisions = getRevisions($ID, $first, $conf['recent']+1);;
417  }
418  $hasNext = false;
419  if (count($revisions)>$conf['recent']) {
420    $hasNext = true;
421    array_pop($revisions); // remove extra log entry
422  }
423
424  $date = @strftime($conf['dformat'],$INFO['lastmod']);
425
426  print p_locale_xhtml('revisions');
427
428  $form = new Doku_Form('page__revisions', wl($ID));
429  $form->addElement(form_makeOpenTag('ul'));
430  if($INFO['exists'] && $first==0){
431    if (isset($INFO['meta']) && isset($INFO['meta']['last_change']) && $INFO['meta']['last_change']['type']===DOKU_CHANGE_TYPE_MINOR_EDIT)
432      $form->addElement(form_makeOpenTag('li', array('class' => 'minor')));
433    else
434      $form->addElement(form_makeOpenTag('li'));
435    $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
436    $form->addElement(form_makeTag('input', array(
437      'type' => 'checkbox',
438      'name' => 'rev2[]',
439      'value' => 'current')));
440
441    $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
442    $form->addElement($date);
443    $form->addElement(form_makeCloseTag('span'));
444
445    $form->addElement(form_makeTag('img', array(
446      'src' =>  DOKU_BASE.'lib/images/blank.gif',
447      'width' => '15',
448      'height' => '11',
449      'alt'    => '')));
450
451    $form->addElement(form_makeOpenTag('a', array(
452      'class' => 'wikilink1',
453      'href'  => wl($ID))));
454    $form->addElement($ID);
455    $form->addElement(form_makeCloseTag('a'));
456
457    $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
458    $form->addElement(' &ndash; ');
459    $form->addElement(htmlspecialchars($INFO['sum']));
460    $form->addElement(form_makeCloseTag('span'));
461
462    $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
463    $form->addElement((empty($INFO['editor']))?('('.$lang['external_edit'].')'):editorinfo($INFO['editor']));
464    $form->addElement(form_makeCloseTag('span'));
465
466    $form->addElement('('.$lang['current'].')');
467    $form->addElement(form_makeCloseTag('div'));
468    $form->addElement(form_makeCloseTag('li'));
469  }
470
471  foreach($revisions as $rev){
472    $date   = strftime($conf['dformat'],$rev);
473    $info   = getRevisionInfo($ID,$rev,true);
474    $exists = page_exists($ID,$rev);
475
476    if ($info['type']===DOKU_CHANGE_TYPE_MINOR_EDIT)
477      $form->addElement(form_makeOpenTag('li', array('class' => 'minor')));
478    else
479      $form->addElement(form_makeOpenTag('li'));
480    $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
481    if($exists){
482      $form->addElement(form_makeTag('input', array(
483        'type' => 'checkbox',
484        'name' => 'rev2[]',
485        'value' => $rev)));
486    }else{
487      $form->addElement(form_makeTag('img', array(
488        'src' => DOKU_BASE.'lib/images/blank.gif',
489        'width' => 14,
490        'height' => 11,
491        'alt' => '')));
492    }
493
494    $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
495    $form->addElement($date);
496    $form->addElement(form_makeCloseTag('span'));
497
498    if($exists){
499      $form->addElement(form_makeOpenTag('a', array('href' => wl($ID,"rev=$rev,do=diff", false, '&'), 'class' => 'diff_link')));
500      $form->addElement(form_makeTag('img', array(
501        'src'    => DOKU_BASE.'lib/images/diff.png',
502        'width'  => 15,
503        'height' => 11,
504        'title'  => $lang['diff'],
505        'alt'    => $lang['diff'])));
506      $form->addElement(form_makeCloseTag('a'));
507
508      $form->addElement(form_makeOpenTag('a', array('href' => wl($ID,"rev=$rev",false,'&'), 'class' => 'wikilink1')));
509      $form->addElement($ID);
510      $form->addElement(form_makeCloseTag('a'));
511    }else{
512      $form->addElement(form_makeTag('img', array(
513        'src' => DOKU_BASE.'lib/images/blank.gif',
514        'width' => '15',
515        'height' => '11',
516        'alt'   => '')));
517      $form->addElement($ID);
518    }
519
520    $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
521    $form->addElement(' &ndash; ');
522    $form->addElement(htmlspecialchars($info['sum']));
523    $form->addElement(form_makeCloseTag('span'));
524
525    $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
526    if($info['user']){
527      $form->addElement(editorinfo($info['user']));
528    }else{
529      $form->addElement($info['ip']);
530    }
531    $form->addElement(form_makeCloseTag('span'));
532
533    $form->addElement(form_makeCloseTag('div'));
534    $form->addElement(form_makeCloseTag('li'));
535  }
536  $form->addElement(form_makeCloseTag('ul'));
537  $form->addElement(form_makeButton('submit', 'diff', $lang['diff2']));
538  html_form('revisions', $form);
539
540  print '<div class="pagenav">';
541  $last = $first + $conf['recent'];
542  if ($first > 0) {
543    $first -= $conf['recent'];
544    if ($first < 0) $first = 0;
545    print '<div class="pagenav-prev">';
546    print html_btn('newer',$ID,"p",array('do' => 'revisions', 'first' => $first));
547    print '</div>';
548  }
549  if ($hasNext) {
550    print '<div class="pagenav-next">';
551    print html_btn('older',$ID,"n",array('do' => 'revisions', 'first' => $last));
552    print '</div>';
553  }
554  print '</div>';
555
556}
557
558/**
559 * display recent changes
560 *
561 * @author Andreas Gohr <andi@splitbrain.org>
562 * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
563 * @author Ben Coburn <btcoburn@silicodon.net>
564 */
565function html_recent($first=0){
566  global $conf;
567  global $lang;
568  global $ID;
569  /* we need to get one additionally log entry to be able to
570   * decide if this is the last page or is there another one.
571   * This is the cheapest solution to get this information.
572   */
573  $recents = getRecents($first,$conf['recent'] + 1,getNS($ID));
574  if(count($recents) == 0 && $first != 0){
575    $first=0;
576    $recents = getRecents($first,$conf['recent'] + 1,getNS($ID));
577  }
578  $hasNext = false;
579  if (count($recents)>$conf['recent']) {
580    $hasNext = true;
581    array_pop($recents); // remove extra log entry
582  }
583
584  print p_locale_xhtml('recent');
585
586  if (getNS($ID) != '')
587    print '<div class="level1"><p>' . sprintf($lang['recent_global'], getNS($ID), wl('', 'do=recent')) . '</p></div>';
588
589  $form = new Doku_Form('dw__recent', script(), 'get');
590  $form->addHidden('sectok', null);
591  $form->addHidden('do', 'recent');
592  $form->addHidden('id', $ID);
593  $form->addElement(form_makeOpenTag('ul'));
594
595  foreach($recents as $recent){
596    $date = strftime($conf['dformat'],$recent['date']);
597    if ($recent['type']===DOKU_CHANGE_TYPE_MINOR_EDIT)
598      $form->addElement(form_makeOpenTag('li', array('class' => 'minor')));
599    else
600      $form->addElement(form_makeOpenTag('li'));
601
602    $form->addElement(form_makeOpenTag('div', array('class' => 'li')));
603
604    $form->addElement(form_makeOpenTag('span', array('class' => 'date')));
605    $form->addElement($date);
606    $form->addElement(form_makeCloseTag('span'));
607
608    $form->addElement(form_makeOpenTag('a', array('class' => 'diff_link', 'href' => wl($recent['id'],"do=diff", false, '&'))));
609    $form->addElement(form_makeTag('img', array(
610      'src'   => DOKU_BASE.'lib/images/diff.png',
611      'width' => 15,
612      'height'=> 11,
613      'title' => $lang['diff'],
614      'alt'   => $lang['diff']
615    )));
616    $form->addElement(form_makeCloseTag('a'));
617
618    $form->addElement(form_makeOpenTag('a', array('class' => 'revisions_link', 'href' => wl($recent['id'],"do=revisions",false,'&'))));
619    $form->addElement(form_makeTag('img', array(
620      'src'   => DOKU_BASE.'lib/images/history.png',
621      'width' => 12,
622      'height'=> 14,
623      'title' => $lang['btn_revs'],
624      'alt'   => $lang['btn_revs']
625    )));
626    $form->addElement(form_makeCloseTag('a'));
627
628    $form->addElement(html_wikilink(':'.$recent['id'],$conf['useheading']?NULL:$recent['id']));
629
630    $form->addElement(form_makeOpenTag('span', array('class' => 'sum')));
631    $form->addElement(' &ndash; '.htmlspecialchars($recent['sum']));
632    $form->addElement(form_makeCloseTag('span'));
633
634    $form->addElement(form_makeOpenTag('span', array('class' => 'user')));
635    if($recent['user']){
636      $form->addElement(editorinfo($recent['user']));
637    }else{
638      $form->addElement($recent['ip']);
639    }
640    $form->addElement(form_makeCloseTag('span'));
641
642    $form->addElement(form_makeCloseTag('div'));
643    $form->addElement(form_makeCloseTag('li'));
644  }
645  $form->addElement(form_makeCloseTag('ul'));
646
647  $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav')));
648  $last = $first + $conf['recent'];
649  if ($first > 0) {
650    $first -= $conf['recent'];
651    if ($first < 0) $first = 0;
652    $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-prev')));
653    $form->addElement(form_makeTag('input', array(
654      'type'  => 'submit',
655      'name'  => 'first['.$first.']',
656      'value' => $lang['btn_newer'],
657      'accesskey' => 'n',
658      'title' => $lang['btn_newer'].' [N]',
659      'class' => 'button'
660    )));
661    $form->addElement(form_makeCloseTag('div'));
662  }
663  if ($hasNext) {
664    $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-next')));
665    $form->addElement(form_makeTag('input', array(
666      'type'  => 'submit',
667      'name'  => 'first['.$last.']',
668      'value' => $lang['btn_older'],
669      'accesskey' => 'p',
670      'title' => $lang['btn_older'].' [P]',
671      'class' => 'button'
672    )));
673    $form->addElement(form_makeCloseTag('div'));
674  }
675  $form->addElement(form_makeCloseTag('div'));
676  html_form('recent', $form);
677}
678
679/**
680 * Display page index
681 *
682 * @author Andreas Gohr <andi@splitbrain.org>
683 */
684function html_index($ns){
685  require_once(DOKU_INC.'inc/search.php');
686  global $conf;
687  global $ID;
688  $dir = $conf['datadir'];
689  $ns  = cleanID($ns);
690  #fixme use appropriate function
691  if(empty($ns)){
692    $ns = dirname(str_replace(':','/',$ID));
693    if($ns == '.') $ns ='';
694  }
695  $ns  = utf8_encodeFN(str_replace(':','/',$ns));
696
697  echo p_locale_xhtml('index');
698  echo '<div id="index__tree">';
699
700  $data = array();
701  search($data,$conf['datadir'],'search_index',array('ns' => $ns));
702  echo html_buildlist($data,'idx','html_list_index','html_li_index');
703
704  echo '</div>';
705}
706
707/**
708 * Index item formatter
709 *
710 * User function for html_buildlist()
711 *
712 * @author Andreas Gohr <andi@splitbrain.org>
713 */
714function html_list_index($item){
715  global $ID;
716  $ret = '';
717  $base = ':'.$item['id'];
718  $base = substr($base,strrpos($base,':')+1);
719  if($item['type']=='d'){
720    $ret .= '<a href="'.wl($ID,'idx='.rawurlencode($item['id'])).'" class="idx_dir"><strong>';
721    $ret .= $base;
722    $ret .= '</strong></a>';
723  }else{
724    $ret .= html_wikilink(':'.$item['id']);
725  }
726  return $ret;
727}
728
729/**
730 * Index List item
731 *
732 * This user function is used in html_build_lidt to build the
733 * <li> tags for namespaces when displaying the page index
734 * it gives different classes to opened or closed "folders"
735 *
736 * @author Andreas Gohr <andi@splitbrain.org>
737 */
738function html_li_index($item){
739  if($item['type'] == "f"){
740    return '<li class="level'.$item['level'].'">';
741  }elseif($item['open']){
742    return '<li class="open">';
743  }else{
744    return '<li class="closed">';
745  }
746}
747
748/**
749 * Default List item
750 *
751 * @author Andreas Gohr <andi@splitbrain.org>
752 */
753function html_li_default($item){
754  return '<li class="level'.$item['level'].'">';
755}
756
757/**
758 * Build an unordered list
759 *
760 * Build an unordered list from the given $data array
761 * Each item in the array has to have a 'level' property
762 * the item itself gets printed by the given $func user
763 * function. The second and optional function is used to
764 * print the <li> tag. Both user function need to accept
765 * a single item.
766 *
767 * Both user functions can be given as array to point to
768 * a member of an object.
769 *
770 * @author Andreas Gohr <andi@splitbrain.org>
771 */
772function html_buildlist($data,$class,$func,$lifunc='html_li_default'){
773  $level = 0;
774  $opens = 0;
775  $ret   = '';
776
777  foreach ($data as $item){
778
779    if( $item['level'] > $level ){
780      //open new list
781      for($i=0; $i<($item['level'] - $level); $i++){
782        if ($i) $ret .= "<li class=\"clear\">\n";
783        $ret .= "\n<ul class=\"$class\">\n";
784      }
785    }elseif( $item['level'] < $level ){
786      //close last item
787      $ret .= "</li>\n";
788      for ($i=0; $i<($level - $item['level']); $i++){
789        //close higher lists
790        $ret .= "</ul>\n</li>\n";
791      }
792    }else{
793      //close last item
794      $ret .= "</li>\n";
795    }
796
797    //remember current level
798    $level = $item['level'];
799
800    //print item
801    $ret .= call_user_func($lifunc,$item);
802    $ret .= '<div class="li">';
803
804    $ret .= call_user_func($func,$item);
805    $ret .= '</div>';
806  }
807
808  //close remaining items and lists
809  for ($i=0; $i < $level; $i++){
810    $ret .= "</li></ul>\n";
811  }
812
813  return $ret;
814}
815
816/**
817 * display backlinks
818 *
819 * @author Andreas Gohr <andi@splitbrain.org>
820 * @author Michael Klier <chi@chimeric.de>
821 */
822function html_backlinks(){
823  require_once(DOKU_INC.'inc/fulltext.php');
824  global $ID;
825  global $conf;
826  global $lang;
827
828  print p_locale_xhtml('backlinks');
829
830  $data = ft_backlinks($ID);
831
832  if(!empty($data)) {
833      print '<ul class="idx">';
834      foreach($data as $blink){
835        print '<li><div class="li">';
836        print html_wikilink(':'.$blink,$conf['useheading']?NULL:$blink);
837        print '</div></li>';
838      }
839      print '</ul>';
840  } else {
841      print '<div class="level1"><p>' . $lang['nothingfound'] . '</p></div>';
842  }
843}
844
845/**
846 * show diff
847 *
848 * @author Andreas Gohr <andi@splitbrain.org>
849 */
850function html_diff($text='',$intro=true){
851  require_once(DOKU_INC.'inc/DifferenceEngine.php');
852  global $ID;
853  global $REV;
854  global $lang;
855  global $conf;
856
857  // we're trying to be clever here, revisions to compare can be either
858  // given as rev and rev2 parameters, with rev2 being optional. Or in an
859  // array in rev2.
860  $rev1 = $REV;
861
862  if(is_array($_REQUEST['rev2'])){
863    $rev1 = (int) $_REQUEST['rev2'][0];
864    $rev2 = (int) $_REQUEST['rev2'][1];
865
866    if(!$rev1){
867        $rev1 = $rev2;
868        unset($rev2);
869    }
870  }else{
871    $rev2 = (int) $_REQUEST['rev2'];
872  }
873
874  if($text){                      // compare text to the most current revision
875    $l_rev   = '';
876    $l_text  = rawWiki($ID,'');
877    $l_head  = '<a class="wikilink1" href="'.wl($ID).'">'.
878               $ID.' '.strftime($conf['dformat'],@filemtime(wikiFN($ID))).'</a> '.
879               $lang['current'];
880
881    $r_rev   = '';
882    $r_text  = cleanText($text);
883    $r_head  = $lang['yours'];
884  }else{
885    if($rev1 && $rev2){            // two specific revisions wanted
886      // make sure order is correct (older on the left)
887      if($rev1 < $rev2){
888        $l_rev = $rev1;
889        $r_rev = $rev2;
890      }else{
891        $l_rev = $rev2;
892        $r_rev = $rev1;
893      }
894    }elseif($rev1){                // single revision given, compare to current
895      $r_rev = '';
896      $l_rev = $rev1;
897    }else{                        // no revision was given, compare previous to current
898      $r_rev = '';
899      $revs = getRevisions($ID, 0, 1);
900      $l_rev = $revs[0];
901    }
902
903    // when both revisions are empty then the page was created just now
904    if(!$l_rev && !$r_rev){
905      $l_text = '';
906    }else{
907      $l_text = rawWiki($ID,$l_rev);
908    }
909    $r_text = rawWiki($ID,$r_rev);
910
911
912    if(!$l_rev){
913      $l_head = '&mdash;';
914    }else{
915      $l_head = '<a class="wikilink1" href="'.wl($ID,"rev=$l_rev").'">'.
916                $ID.' '.strftime($conf['dformat'],$l_rev).'</a>';
917    }
918
919    if($r_rev){
920      $r_head = '<a class="wikilink1" href="'.wl($ID,"rev=$r_rev").'">'.
921                $ID.' '.strftime($conf['dformat'],$r_rev).'</a>';
922    }elseif($_rev = @filemtime(wikiFN($ID))){
923      $r_head  = '<a class="wikilink1" href="'.wl($ID).'">'.
924               $ID.' '.strftime($conf['dformat'],$_rev).'</a> '.
925               $lang['current'];
926    }else{
927      $r_head = '&mdash; '.$lang['current'];
928    }
929  }
930
931  $df = new Diff(explode("\n",htmlspecialchars($l_text)),
932                 explode("\n",htmlspecialchars($r_text)));
933
934  $tdf = new TableDiffFormatter();
935  if($intro) print p_locale_xhtml('diff');
936  ?>
937    <table class="diff">
938      <tr>
939        <th colspan="2">
940          <?php echo $l_head?>
941        </th>
942        <th colspan="2">
943          <?php echo $r_head?>
944        </th>
945      </tr>
946      <?php echo $tdf->format($df)?>
947    </table>
948  <?php
949}
950
951/**
952 * show warning on conflict detection
953 *
954 * @author Andreas Gohr <andi@splitbrain.org>
955 */
956function html_conflict($text,$summary){
957  global $ID;
958  global $lang;
959
960  print p_locale_xhtml('conflict');
961  $form = new Doku_Form('dw__editform');
962  $form->addHidden('id', $ID);
963  $form->addHidden('wikitext', $text);
964  $form->addHidden('summary', $summary);
965  $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('accesskey'=>'s')));
966  $form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel']));
967  html_form('conflict', $form);
968  print '<br /><br /><br /><br />'.NL;
969}
970
971/**
972 * Prints the global message array
973 *
974 * @author Andreas Gohr <andi@splitbrain.org>
975 */
976function html_msgarea(){
977  global $MSG;
978
979  if(!isset($MSG)) return;
980
981  foreach($MSG as $msg){
982    print '<div class="'.$msg['lvl'].'">';
983    print $msg['msg'];
984    print '</div>';
985  }
986}
987
988/**
989 * Prints the registration form
990 *
991 * @author Andreas Gohr <andi@splitbrain.org>
992 */
993function html_register(){
994  global $lang;
995  global $conf;
996  global $ID;
997
998  print p_locale_xhtml('register');
999  print '<div class="centeralign">'.NL;
1000  $form = new Doku_Form('dw__register', wl($ID));
1001  $form->startFieldset($lang['register']);
1002  $form->addHidden('do', 'register');
1003  $form->addHidden('save', '1');
1004  $form->addElement(form_makeTextField('login', $_POST['login'], $lang['user'], null, 'block', array('size'=>'50')));
1005  if (!$conf['autopasswd']) {
1006    $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', array('size'=>'50')));
1007    $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
1008  }
1009  $form->addElement(form_makeTextField('fullname', $_POST['fullname'], $lang['fullname'], '', 'block', array('size'=>'50')));
1010  $form->addElement(form_makeTextField('email', $_POST['email'], $lang['email'], '', 'block', array('size'=>'50')));
1011  $form->addElement(form_makeButton('submit', '', $lang['register']));
1012  $form->endFieldset();
1013  html_form('register', $form);
1014
1015  print '</div>'.NL;
1016}
1017
1018/**
1019 * Print the update profile form
1020 *
1021 * @author Christopher Smith <chris@jalakai.co.uk>
1022 * @author Andreas Gohr <andi@splitbrain.org>
1023 */
1024function html_updateprofile(){
1025  global $lang;
1026  global $conf;
1027  global $ID;
1028  global $INFO;
1029  global $auth;
1030
1031  print p_locale_xhtml('updateprofile');
1032
1033  if (empty($_POST['fullname'])) $_POST['fullname'] = $INFO['userinfo']['name'];
1034  if (empty($_POST['email'])) $_POST['email'] = $INFO['userinfo']['mail'];
1035  print '<div class="centeralign">'.NL;
1036  $form = new Doku_Form('dw__register', wl($ID));
1037  $form->startFieldset($lang['profile']);
1038  $form->addHidden('do', 'profile');
1039  $form->addHidden('save', '1');
1040  $form->addElement(form_makeTextField('fullname', $_SERVER['REMOTE_USER'], $lang['user'], '', 'block', array('size'=>'50', 'disabled'=>'disabled')));
1041  $attr = array('size'=>'50');
1042  if (!$auth->canDo('modName')) $attr['disabled'] = 'disabled';
1043  $form->addElement(form_makeTextField('fullname', $_POST['fullname'], $lang['fullname'], '', 'block', $attr));
1044  $attr = array('size'=>'50');
1045  if (!$auth->canDo('modMail')) $attr['disabled'] = 'disabled';
1046  $form->addElement(form_makeTextField('email', $_POST['email'], $lang['email'], '', 'block', $attr));
1047  $form->addElement(form_makeTag('br'));
1048  if ($auth->canDo('modPass')) {
1049    $form->addElement(form_makePasswordField('newpass', $lang['newpass'], '', 'block', array('size'=>'50')));
1050    $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
1051  }
1052  if ($conf['profileconfirm']) {
1053    $form->addElement(form_makeTag('br'));
1054    $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50')));
1055  }
1056  $form->addElement(form_makeButton('submit', '', $lang['btn_save']));
1057  $form->addElement(form_makeButton('reset', '', $lang['btn_reset']));
1058  $form->endFieldset();
1059  html_form('updateprofile', $form);
1060  print '</div>'.NL;
1061}
1062
1063/**
1064 * This displays the edit form (lots of logic included)
1065 *
1066 * @fixme    this is a huge lump of code and should be modularized
1067 * @triggers HTML_PAGE_FROMTEMPLATE
1068 * @triggers HTML_EDITFORM_INJECTION
1069 * @author   Andreas Gohr <andi@splitbrain.org>
1070 */
1071function html_edit($text=null,$include='edit'){ //FIXME: include needed?
1072  global $ID;
1073  global $REV;
1074  global $DATE;
1075  global $RANGE;
1076  global $PRE;
1077  global $SUF;
1078  global $INFO;
1079  global $SUM;
1080  global $lang;
1081  global $conf;
1082  global $license;
1083
1084  //set summary default
1085  if(!$SUM){
1086    if($REV){
1087      $SUM = $lang['restored'];
1088    }elseif(!$INFO['exists']){
1089      $SUM = $lang['created'];
1090    }
1091  }
1092
1093  //no text? Load it!
1094  if(!isset($text)){
1095    $pr = false; //no preview mode
1096    if($INFO['exists']){
1097      if($RANGE){
1098        list($PRE,$text,$SUF) = rawWikiSlices($RANGE,$ID,$REV);
1099      }else{
1100        $text = rawWiki($ID,$REV);
1101      }
1102      $check = md5($text);
1103      $mod = false;
1104    }else{
1105      //try to load a pagetemplate
1106      $data = array($ID);
1107      $text = trigger_event('HTML_PAGE_FROMTEMPLATE',$data,'pageTemplate',true);
1108      $check = md5('');
1109      $mod = $text!=='';
1110    }
1111  }else{
1112    $pr = true; //preview mode
1113    if (isset($_REQUEST['changecheck'])) {
1114      $check = $_REQUEST['changecheck'];
1115      $mod = md5($text)!==$check;
1116    } else {
1117      // Why? Assume default text is unmodified.
1118      $check = md5($text);
1119      $mod = false;
1120    }
1121  }
1122
1123  $wr = $INFO['writable'] && !$INFO['locked'];
1124  if($wr){
1125    if ($REV) print p_locale_xhtml('editrev');
1126    print p_locale_xhtml($include);
1127  }else{
1128    // check pseudo action 'source'
1129    if(!actionOK('source')){
1130      msg('Command disabled: source',-1);
1131      return;
1132    }
1133    print p_locale_xhtml('read');
1134  }
1135  if(!$DATE) $DATE = $INFO['lastmod'];
1136
1137
1138?>
1139  <div style="width:99%;">
1140
1141   <div class="toolbar">
1142      <div id="draft__status"><?php if(!empty($INFO['draft'])) echo $lang['draftdate'].' '.strftime($conf['dformat']);?></div>
1143      <div id="tool__bar"><?php if($wr){?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
1144      target="_blank"><?php echo $lang['mediaselect'] ?></a><?php }?></div>
1145
1146      <?php if($wr){?>
1147      <script type="text/javascript" charset="utf-8"><!--//--><![CDATA[//><!--
1148        <?php /* sets changed to true when previewed */?>
1149        textChanged = <?php ($mod) ? print 'true' : print 'false' ?>;
1150      //--><!]]></script>
1151      <span id="spell__action"></span>
1152      <div id="spell__suggest"></div>
1153      <?php } ?>
1154   </div>
1155   <div id="spell__result"></div>
1156<?php
1157  $form = new Doku_Form('dw__editform');
1158  $form->addHidden('id', $ID);
1159  $form->addHidden('rev', $REV);
1160  $form->addHidden('date', $DATE);
1161  $form->addHidden('prefix', $PRE);
1162  $form->addHidden('suffix', $SUF);
1163  $form->addHidden('changecheck', $check);
1164  $attr = array('tabindex'=>'1');
1165  if (!$wr) $attr['readonly'] = 'readonly';
1166  $form->addElement(form_makeWikiText($text, $attr));
1167  $form->addElement(form_makeOpenTag('div', array('id'=>'wiki__editbar')));
1168  $form->addElement(form_makeOpenTag('div', array('id'=>'size__ctl')));
1169  $form->addElement(form_makeCloseTag('div'));
1170  if ($wr) {
1171    $form->addElement(form_makeOpenTag('div', array('class'=>'editButtons')));
1172    $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('id'=>'edbtn__save', 'accesskey'=>'s', 'tabindex'=>'4')));
1173    $form->addElement(form_makeButton('submit', 'preview', $lang['btn_preview'], array('id'=>'edbtn__preview', 'accesskey'=>'p', 'tabindex'=>'5')));
1174    $form->addElement(form_makeButton('submit', 'draftdel', $lang['btn_cancel'], array('tabindex'=>'6')));
1175    $form->addElement(form_makeCloseTag('div'));
1176    $form->addElement(form_makeOpenTag('div', array('class'=>'summary')));
1177    $form->addElement(form_makeTextField('summary', $SUM, $lang['summary'], 'edit__summary', 'nowrap', array('size'=>'50', 'tabindex'=>'2')));
1178    $elem = html_minoredit();
1179    if ($elem) $form->addElement($elem);
1180    $form->addElement(form_makeCloseTag('div'));
1181  }
1182  $form->addElement(form_makeCloseTag('div'));
1183  if($conf['license']){
1184    $form->addElement(form_makeOpenTag('div', array('class'=>'license')));
1185    $out  = $lang['licenseok'];
1186    $out .= '<a href="'.$license[$conf['license']]['url'].'" rel="license" class="urlextern"';
1187    if($conf['target']['external']) $out .= ' target="'.$conf['target']['external'].'"';
1188    $out .= '> '.$license[$conf['license']]['name'].'</a>';
1189    $form->addElement($out);
1190    $form->addElement(form_makeCloseTag('div'));
1191  }
1192  html_form('edit', $form);
1193  print '</div>'.NL;
1194}
1195
1196/**
1197 * Adds a checkbox for minor edits for logged in users
1198 *
1199 * @author Andrea Gohr <andi@splitbrain.org>
1200 */
1201function html_minoredit(){
1202  global $conf;
1203  global $lang;
1204  // minor edits are for logged in users only
1205  if(!$conf['useacl'] || !$_SERVER['REMOTE_USER']){
1206    return false;
1207  }
1208
1209  $p = array();
1210  $p['tabindex'] = 3;
1211  if(!empty($_REQUEST['minor'])) $p['checked']='checked';
1212  return form_makeCheckboxField('minor', '1', $lang['minoredit'], 'minoredit', 'nowrap', $p);
1213}
1214
1215/**
1216 * prints some debug info
1217 *
1218 * @author Andreas Gohr <andi@splitbrain.org>
1219 */
1220function html_debug(){
1221  global $conf;
1222  global $lang;
1223  global $auth;
1224  global $INFO;
1225
1226  //remove sensitive data
1227  $cnf = $conf;
1228  debug_guard($cnf);
1229  $nfo = $INFO;
1230  debug_guard($nfo);
1231  $ses = $_SESSION;
1232  debug_guard($ses);
1233
1234  print '<html><body>';
1235
1236  print '<p>When reporting bugs please send all the following ';
1237  print 'output as a mail to andi@splitbrain.org ';
1238  print 'The best way to do this is to save this page in your browser</p>';
1239
1240  print '<b>$INFO:</b><pre>';
1241  print_r($nfo);
1242  print '</pre>';
1243
1244  print '<b>$_SERVER:</b><pre>';
1245  print_r($_SERVER);
1246  print '</pre>';
1247
1248  print '<b>$conf:</b><pre>';
1249  print_r($cnf);
1250  print '</pre>';
1251
1252  print '<b>DOKU_BASE:</b><pre>';
1253  print DOKU_BASE;
1254  print '</pre>';
1255
1256  print '<b>abs DOKU_BASE:</b><pre>';
1257  print DOKU_URL;
1258  print '</pre>';
1259
1260  print '<b>rel DOKU_BASE:</b><pre>';
1261  print dirname($_SERVER['PHP_SELF']).'/';
1262  print '</pre>';
1263
1264  print '<b>PHP Version:</b><pre>';
1265  print phpversion();
1266  print '</pre>';
1267
1268  print '<b>locale:</b><pre>';
1269  print setlocale(LC_ALL,0);
1270  print '</pre>';
1271
1272  print '<b>encoding:</b><pre>';
1273  print $lang['encoding'];
1274  print '</pre>';
1275
1276  if($auth){
1277    print '<b>Auth backend capabilities:</b><pre>';
1278    print_r($auth->cando);
1279    print '</pre>';
1280  }
1281
1282  print '<b>$_SESSION:</b><pre>';
1283  print_r($ses);
1284  print '</pre>';
1285
1286  print '<b>Environment:</b><pre>';
1287  print_r($_ENV);
1288  print '</pre>';
1289
1290  print '<b>PHP settings:</b><pre>';
1291  $inis = ini_get_all();
1292  print_r($inis);
1293  print '</pre>';
1294
1295  print '</body></html>';
1296}
1297
1298function html_admin(){
1299  global $ID;
1300  global $INFO;
1301  global $lang;
1302  global $conf;
1303
1304  print p_locale_xhtml('admin');
1305
1306  // build menu of admin functions from the plugins that handle them
1307  $pluginlist = plugin_list('admin');
1308  $menu = array();
1309  foreach ($pluginlist as $p) {
1310    if($obj =& plugin_load('admin',$p) === NULL) continue;
1311
1312    // check permissions
1313    if($obj->forAdminOnly() && !$INFO['isadmin']) continue;
1314
1315    $menu[] = array('plugin' => $p,
1316                    'prompt' => $obj->getMenuText($conf['lang']),
1317                    'sort' => $obj->getMenuSort()
1318                   );
1319  }
1320
1321  usort($menu, 'p_sort_modes');
1322
1323  // output the menu
1324  ptln('<ul>');
1325
1326  foreach ($menu as $item) {
1327    if (!$item['prompt']) continue;
1328    ptln('  <li><div class="li"><a href="'.wl($ID, 'do=admin&amp;page='.$item['plugin']).'">'.$item['prompt'].'</a></div></li>');
1329  }
1330
1331  ptln('</ul>');
1332}
1333
1334/**
1335 * Form to request a new password for an existing account
1336 *
1337 * @author Benoit Chesneau <benoit@bchesneau.info>
1338 */
1339function html_resendpwd() {
1340  global $lang;
1341  global $conf;
1342  global $ID;
1343
1344  print p_locale_xhtml('resendpwd');
1345  print '<div class="centeralign">'.NL;
1346  $form = new Doku_Form('dw__resendpwd', wl($ID));
1347  $form->startFieldset($lang['resendpwd']);
1348  $form->addHidden('do', 'resendpwd');
1349  $form->addHidden('save', '1');
1350  $form->addElement(form_makeTag('br'));
1351  $form->addElement(form_makeTextField('login', $_POST['login'], $lang['user'], '', 'block'));
1352  $form->addElement(form_makeTag('br'));
1353  $form->addElement(form_makeTag('br'));
1354  $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
1355  $form->endFieldset();
1356  html_form('resendpwd', $form);
1357  print '</div>'.NL;
1358}
1359
1360/**
1361 * Return the TOC rendered to XHTML
1362 *
1363 * @author Andreas Gohr <andi@splitbrain.org>
1364 */
1365function html_TOC($toc){
1366    if(!count($toc)) return '';
1367    global $lang;
1368    $out  = '<!-- TOC START -->'.DOKU_LF;
1369    $out .= '<div class="toc">'.DOKU_LF;
1370    $out .= '<div class="tocheader toctoggle" id="toc__header">';
1371    $out .= $lang['toc'];
1372    $out .= '</div>'.DOKU_LF;
1373    $out .= '<div id="toc__inside">'.DOKU_LF;
1374    $out .= html_buildlist($toc,'toc','html_list_toc');
1375    $out .= '</div>'.DOKU_LF.'</div>'.DOKU_LF;
1376    $out .= '<!-- TOC END -->'.DOKU_LF;
1377    return $out;                                                                                                }
1378
1379/**
1380 * Callback for html_buildlist
1381 */
1382function html_list_toc($item){
1383    if($item['hid']){
1384        $link = '#'.$item['hid'];
1385    }else{
1386        $link = $item['link'];
1387    }
1388
1389    return '<span class="li"><a href="'.$link.'" class="toc">'.
1390           hsc($item['title']).'</a></span>';
1391}
1392
1393/**
1394 * Helper function to build TOC items
1395 *
1396 * Returns an array ready to be added to a TOC array
1397 *
1398 * @param string $link  - where to link (if $hash set to '#' it's a local anchor)
1399 * @param string $text  - what to display in the TOC
1400 * @param int    $level - nesting level
1401 * @param string $hash  - is prepended to the given $link, set blank if you want full links
1402 */
1403function html_mktocitem($link, $text, $level, $hash='#'){
1404    global $conf;
1405    return  array( 'link'  => $hash.$link,
1406                   'title' => $text,
1407                   'type'  => 'ul',
1408                   'level' => $level);
1409}
1410
1411/**
1412 * Output a Doku_Form object.
1413 * Triggers an event with the form name: HTML_{$name}FORM_OUTPUT
1414 *
1415 * @author Tom N Harris <tnharris@whoopdedo.org>
1416 */
1417function html_form($name, &$form) {
1418  // Safety check in case the caller forgets.
1419  $form->endFieldset();
1420  trigger_event('HTML_'.strtoupper($name).'FORM_OUTPUT', $form, 'html_form_output', false);
1421}
1422
1423/**
1424 * Form print function.
1425 * Just calls printForm() on the data object.
1426 */
1427function html_form_output($data) {
1428  $data->printForm();
1429}
1430
1431//Setup VIM: ex: et ts=2 enc=utf-8 :
1432