xref: /dokuwiki/inc/html.php (revision 20e29859d7134c28e50a97c828f78aa7fe719352)
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' => '[ALT+N]'
659    )));
660    $form->addElement(form_makeCloseTag('div'));
661  }
662  if ($hasNext) {
663    $form->addElement(form_makeOpenTag('div', array('class' => 'pagenav-next')));
664    $form->addElement(form_makeTag('input', array(
665      'type'  => 'submit',
666      'name'  => 'first['.$last.']',
667      'value' => $lang['btn_older'],
668      'accesskey' => 'p',
669      'title'  => '[ALT+P]'
670    )));
671    $form->addElement(form_makeCloseTag('div'));
672  }
673  $form->addElement(form_makeCloseTag('div'));
674  html_form('recent', $form);
675}
676
677/**
678 * Display page index
679 *
680 * @author Andreas Gohr <andi@splitbrain.org>
681 */
682function html_index($ns){
683  require_once(DOKU_INC.'inc/search.php');
684  global $conf;
685  global $ID;
686  $dir = $conf['datadir'];
687  $ns  = cleanID($ns);
688  #fixme use appropriate function
689  if(empty($ns)){
690    $ns = dirname(str_replace(':','/',$ID));
691    if($ns == '.') $ns ='';
692  }
693  $ns  = utf8_encodeFN(str_replace(':','/',$ns));
694
695  echo p_locale_xhtml('index');
696  echo '<div id="index__tree">';
697
698  $data = array();
699  search($data,$conf['datadir'],'search_index',array('ns' => $ns));
700  echo html_buildlist($data,'idx','html_list_index','html_li_index');
701
702  echo '</div>';
703}
704
705/**
706 * Index item formatter
707 *
708 * User function for html_buildlist()
709 *
710 * @author Andreas Gohr <andi@splitbrain.org>
711 */
712function html_list_index($item){
713  global $ID;
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='.rawurlencode($item['id'])).'" class="idx_dir"><strong>';
719    $ret .= $base;
720    $ret .= '</strong></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 * Both user functions can be given as array to point to
766 * a member of an object.
767 *
768 * @author Andreas Gohr <andi@splitbrain.org>
769 */
770function html_buildlist($data,$class,$func,$lifunc='html_li_default'){
771  $level = 0;
772  $opens = 0;
773  $ret   = '';
774
775  foreach ($data as $item){
776
777    if( $item['level'] > $level ){
778      //open new list
779      for($i=0; $i<($item['level'] - $level); $i++){
780        if ($i) $ret .= "<li class=\"clear\">\n";
781        $ret .= "\n<ul class=\"$class\">\n";
782      }
783    }elseif( $item['level'] < $level ){
784      //close last item
785      $ret .= "</li>\n";
786      for ($i=0; $i<($level - $item['level']); $i++){
787        //close higher lists
788        $ret .= "</ul>\n</li>\n";
789      }
790    }else{
791      //close last item
792      $ret .= "</li>\n";
793    }
794
795    //remember current level
796    $level = $item['level'];
797
798    //print item
799    $ret .= call_user_func($lifunc,$item);
800    $ret .= '<div class="li">';
801
802    $ret .= call_user_func($func,$item);
803    $ret .= '</div>';
804  }
805
806  //close remaining items and lists
807  for ($i=0; $i < $level; $i++){
808    $ret .= "</li></ul>\n";
809  }
810
811  return $ret;
812}
813
814/**
815 * display backlinks
816 *
817 * @author Andreas Gohr <andi@splitbrain.org>
818 * @author Michael Klier <chi@chimeric.de>
819 */
820function html_backlinks(){
821  require_once(DOKU_INC.'inc/fulltext.php');
822  global $ID;
823  global $conf;
824  global $lang;
825
826  print p_locale_xhtml('backlinks');
827
828  $data = ft_backlinks($ID);
829
830  if(!empty($data)) {
831      print '<ul class="idx">';
832      foreach($data as $blink){
833        print '<li><div class="li">';
834        print html_wikilink(':'.$blink,$conf['useheading']?NULL:$blink);
835        print '</div></li>';
836      }
837      print '</ul>';
838  } else {
839      print '<div class="level1"><p>' . $lang['nothingfound'] . '</p></div>';
840  }
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
855  // we're trying to be clever here, revisions to compare can be either
856  // given as rev and rev2 parameters, with rev2 being optional. Or in an
857  // array in rev2.
858  $rev1 = $REV;
859
860  if(is_array($_REQUEST['rev2'])){
861    $rev1 = (int) $_REQUEST['rev2'][0];
862    $rev2 = (int) $_REQUEST['rev2'][1];
863
864    if(!$rev1){
865        $rev1 = $rev2;
866        unset($rev2);
867    }
868  }else{
869    $rev2 = (int) $_REQUEST['rev2'];
870  }
871
872  if($text){                      // compare text to the most current revision
873    $l_rev   = '';
874    $l_text  = rawWiki($ID,'');
875    $l_head  = '<a class="wikilink1" href="'.wl($ID).'">'.
876               $ID.' '.strftime($conf['dformat'],@filemtime(wikiFN($ID))).'</a> '.
877               $lang['current'];
878
879    $r_rev   = '';
880    $r_text  = cleanText($text);
881    $r_head  = $lang['yours'];
882  }else{
883    if($rev1 && $rev2){            // two specific revisions wanted
884      // make sure order is correct (older on the left)
885      if($rev1 < $rev2){
886        $l_rev = $rev1;
887        $r_rev = $rev2;
888      }else{
889        $l_rev = $rev2;
890        $r_rev = $rev1;
891      }
892    }elseif($rev1){                // single revision given, compare to current
893      $r_rev = '';
894      $l_rev = $rev1;
895    }else{                        // no revision was given, compare previous to current
896      $r_rev = '';
897      $revs = getRevisions($ID, 0, 1);
898      $l_rev = $revs[0];
899    }
900
901    // when both revisions are empty then the page was created just now
902    if(!$l_rev && !$r_rev){
903      $l_text = '';
904    }else{
905      $l_text = rawWiki($ID,$l_rev);
906    }
907    $r_text = rawWiki($ID,$r_rev);
908
909
910    if(!$l_rev){
911      $l_head = '&mdash;';
912    }else{
913      $l_head = '<a class="wikilink1" href="'.wl($ID,"rev=$l_rev").'">'.
914                $ID.' '.strftime($conf['dformat'],$l_rev).'</a>';
915    }
916
917    if($r_rev){
918      $r_head = '<a class="wikilink1" href="'.wl($ID,"rev=$r_rev").'">'.
919                $ID.' '.strftime($conf['dformat'],$r_rev).'</a>';
920    }elseif($_rev = @filemtime(wikiFN($ID))){
921      $r_head  = '<a class="wikilink1" href="'.wl($ID).'">'.
922               $ID.' '.strftime($conf['dformat'],$_rev).'</a> '.
923               $lang['current'];
924    }else{
925      $r_head = '&mdash; '.$lang['current'];
926    }
927  }
928
929  $df = new Diff(explode("\n",htmlspecialchars($l_text)),
930                 explode("\n",htmlspecialchars($r_text)));
931
932  $tdf = new TableDiffFormatter();
933  if($intro) print p_locale_xhtml('diff');
934  ?>
935    <table class="diff">
936      <tr>
937        <th colspan="2">
938          <?php echo $l_head?>
939        </th>
940        <th colspan="2">
941          <?php echo $r_head?>
942        </th>
943      </tr>
944      <?php echo $tdf->format($df)?>
945    </table>
946  <?php
947}
948
949/**
950 * show warning on conflict detection
951 *
952 * @author Andreas Gohr <andi@splitbrain.org>
953 */
954function html_conflict($text,$summary){
955  global $ID;
956  global $lang;
957
958  print p_locale_xhtml('conflict');
959  $form = new Doku_Form('dw__editform');
960  $form->addHidden('id', $ID);
961  $form->addHidden('wikitext', $text);
962  $form->addHidden('summary', $summary);
963  $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('accesskey'=>'s')));
964  $form->addElement(form_makeButton('submit', 'cancel', $lang['btn_cancel']));
965  html_form('conflict', $form);
966  print '<br /><br /><br /><br />'.NL;
967}
968
969/**
970 * Prints the global message array
971 *
972 * @author Andreas Gohr <andi@splitbrain.org>
973 */
974function html_msgarea(){
975  global $MSG;
976
977  if(!isset($MSG)) return;
978
979  foreach($MSG as $msg){
980    print '<div class="'.$msg['lvl'].'">';
981    print $msg['msg'];
982    print '</div>';
983  }
984}
985
986/**
987 * Prints the registration form
988 *
989 * @author Andreas Gohr <andi@splitbrain.org>
990 */
991function html_register(){
992  global $lang;
993  global $conf;
994  global $ID;
995
996  print p_locale_xhtml('register');
997  print '<div class="centeralign">'.NL;
998  $form = new Doku_Form('dw__register', wl($ID));
999  $form->startFieldset($lang['register']);
1000  $form->addHidden('do', 'register');
1001  $form->addHidden('save', '1');
1002  $form->addElement(form_makeTextField('login', $_POST['login'], $lang['user'], null, 'block', array('size'=>'50')));
1003  if (!$conf['autopasswd']) {
1004    $form->addElement(form_makePasswordField('pass', $lang['pass'], '', 'block', array('size'=>'50')));
1005    $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
1006  }
1007  $form->addElement(form_makeTextField('fullname', $_POST['fullname'], $lang['fullname'], '', 'block', array('size'=>'50')));
1008  $form->addElement(form_makeTextField('email', $_POST['email'], $lang['email'], '', 'block', array('size'=>'50')));
1009  $form->addElement(form_makeButton('submit', '', $lang['register']));
1010  $form->endFieldset();
1011  html_form('register', $form);
1012
1013  print '</div>'.NL;
1014}
1015
1016/**
1017 * Print the update profile form
1018 *
1019 * @author Christopher Smith <chris@jalakai.co.uk>
1020 * @author Andreas Gohr <andi@splitbrain.org>
1021 */
1022function html_updateprofile(){
1023  global $lang;
1024  global $conf;
1025  global $ID;
1026  global $INFO;
1027  global $auth;
1028
1029  print p_locale_xhtml('updateprofile');
1030
1031  if (empty($_POST['fullname'])) $_POST['fullname'] = $INFO['userinfo']['name'];
1032  if (empty($_POST['email'])) $_POST['email'] = $INFO['userinfo']['mail'];
1033  print '<div class="centeralign">'.NL;
1034  $form = new Doku_Form('dw__register', wl($ID));
1035  $form->startFieldset($lang['profile']);
1036  $form->addHidden('do', 'profile');
1037  $form->addHidden('save', '1');
1038  $form->addElement(form_makeTextField('fullname', $_SERVER['REMOTE_USER'], $lang['user'], '', 'block', array('size'=>'50', 'disabled'=>'disabled')));
1039  $attr = array('size'=>'50');
1040  if (!$auth->canDo('modName')) $attr['disabled'] = 'disabled';
1041  $form->addElement(form_makeTextField('fullname', $_POST['fullname'], $lang['fullname'], '', 'block', $attr));
1042  $attr = array('size'=>'50');
1043  if (!$auth->canDo('modMail')) $attr['disabled'] = 'disabled';
1044  $form->addElement(form_makeTextField('email', $_POST['email'], $lang['email'], '', 'block', $attr));
1045  $form->addElement(form_makeTag('br'));
1046  if ($auth->canDo('modPass')) {
1047    $form->addElement(form_makePasswordField('newpass', $lang['newpass'], '', 'block', array('size'=>'50')));
1048    $form->addElement(form_makePasswordField('passchk', $lang['passchk'], '', 'block', array('size'=>'50')));
1049  }
1050  if ($conf['profileconfirm']) {
1051    $form->addElement(form_makeTag('br'));
1052    $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50')));
1053  }
1054  $form->addElement(form_makeButton('submit', '', $lang['btn_save']));
1055  $form->addElement(form_makeButton('reset', '', $lang['btn_reset']));
1056  $form->endFieldset();
1057  html_form('updateprofile', $form);
1058  print '</div>'.NL;
1059}
1060
1061/**
1062 * This displays the edit form (lots of logic included)
1063 *
1064 * @fixme    this is a huge lump of code and should be modularized
1065 * @triggers HTML_PAGE_FROMTEMPLATE
1066 * @triggers HTML_EDITFORM_INJECTION
1067 * @author   Andreas Gohr <andi@splitbrain.org>
1068 */
1069function html_edit($text=null,$include='edit'){ //FIXME: include needed?
1070  global $ID;
1071  global $REV;
1072  global $DATE;
1073  global $RANGE;
1074  global $PRE;
1075  global $SUF;
1076  global $INFO;
1077  global $SUM;
1078  global $lang;
1079  global $conf;
1080  global $license;
1081
1082  //set summary default
1083  if(!$SUM){
1084    if($REV){
1085      $SUM = $lang['restored'];
1086    }elseif(!$INFO['exists']){
1087      $SUM = $lang['created'];
1088    }
1089  }
1090
1091  //no text? Load it!
1092  if(!isset($text)){
1093    $pr = false; //no preview mode
1094    if($INFO['exists']){
1095      if($RANGE){
1096        list($PRE,$text,$SUF) = rawWikiSlices($RANGE,$ID,$REV);
1097      }else{
1098        $text = rawWiki($ID,$REV);
1099      }
1100      $check = md5($text);
1101      $mod = false;
1102    }else{
1103      //try to load a pagetemplate
1104      $data = array($ID);
1105      $text = trigger_event('HTML_PAGE_FROMTEMPLATE',$data,'pageTemplate',true);
1106      $check = md5('');
1107      $mod = $text!=='';
1108    }
1109  }else{
1110    $pr = true; //preview mode
1111    if (isset($_REQUEST['changecheck'])) {
1112      $check = $_REQUEST['changecheck'];
1113      $mod = md5($text)!==$check;
1114    } else {
1115      // Why? Assume default text is unmodified.
1116      $check = md5($text);
1117      $mod = false;
1118    }
1119  }
1120
1121  $wr = $INFO['writable'] && !$INFO['locked'];
1122  if($wr){
1123    if ($REV) print p_locale_xhtml('editrev');
1124    print p_locale_xhtml($include);
1125  }else{
1126    // check pseudo action 'source'
1127    if(!actionOK('source')){
1128      msg('Command disabled: source',-1);
1129      return;
1130    }
1131    print p_locale_xhtml('read');
1132  }
1133  if(!$DATE) $DATE = $INFO['lastmod'];
1134
1135
1136?>
1137  <div style="width:99%;">
1138
1139   <div class="toolbar">
1140      <div id="draft__status"><?php if(!empty($INFO['draft'])) echo $lang['draftdate'].' '.strftime($conf['dformat']);?></div>
1141      <div id="tool__bar"><?php if($wr){?><a href="<?php echo DOKU_BASE?>lib/exe/mediamanager.php?ns=<?php echo $INFO['namespace']?>"
1142      target="_blank"><?php echo $lang['mediaselect'] ?></a><?php }?></div>
1143
1144      <?php if($wr){?>
1145      <script type="text/javascript" charset="utf-8"><!--//--><![CDATA[//><!--
1146        <?php /* sets changed to true when previewed */?>
1147        textChanged = <?php ($mod) ? print 'true' : print 'false' ?>;
1148      //--><!]]></script>
1149      <span id="spell__action"></span>
1150      <div id="spell__suggest"></div>
1151      <?php } ?>
1152   </div>
1153   <div id="spell__result"></div>
1154<?php
1155  $form = new Doku_Form('dw__editform');
1156  $form->addHidden('id', $ID);
1157  $form->addHidden('rev', $REV);
1158  $form->addHidden('date', $DATE);
1159  $form->addHidden('prefix', $PRE);
1160  $form->addHidden('suffix', $SUF);
1161  $form->addHidden('changecheck', $check);
1162  $attr = array('tabindex'=>'1');
1163  if (!$wr) $attr['readonly'] = 'readonly';
1164  $form->addElement(form_makeWikiText($text, $attr));
1165  $form->addElement(form_makeOpenTag('div', array('id'=>'wiki__editbar')));
1166  $form->addElement(form_makeOpenTag('div', array('id'=>'size__ctl')));
1167  $form->addElement(form_makeCloseTag('div'));
1168  if ($wr) {
1169    $form->addElement(form_makeOpenTag('div', array('class'=>'editButtons')));
1170    $form->addElement(form_makeButton('submit', 'save', $lang['btn_save'], array('id'=>'edbtn__save', 'accesskey'=>'s', 'tabindex'=>'4')));
1171    $form->addElement(form_makeButton('submit', 'preview', $lang['btn_preview'], array('id'=>'edbtn__preview', 'accesskey'=>'p', 'tabindex'=>'5')));
1172    $form->addElement(form_makeButton('submit', 'draftdel', $lang['btn_cancel'], array('tabindex'=>'6')));
1173    $form->addElement(form_makeCloseTag('div'));
1174    $form->addElement(form_makeOpenTag('div', array('class'=>'summary')));
1175    $form->addElement(form_makeTextField('summary', $SUM, $lang['summary'], 'edit__summary', 'nowrap', array('size'=>'50', 'tabindex'=>'2')));
1176    $elem = html_minoredit();
1177    if ($elem) $form->addElement($elem);
1178    $form->addElement(form_makeCloseTag('div'));
1179  }
1180  $form->addElement(form_makeCloseTag('div'));
1181  if($conf['license']){
1182    $form->addElement(form_makeOpenTag('div', array('class'=>'license')));
1183    $out  = $lang['licenseok'];
1184    $out .= '<a href="'.$license[$conf['license']]['url'].'" rel="license" class="urlextern"';
1185    if($conf['target']['external']) $out .= ' target="'.$conf['target']['external'].'"';
1186    $out .= '> '.$license[$conf['license']]['name'].'</a>';
1187    $form->addElement($out);
1188    $form->addElement(form_makeCloseTag('div'));
1189  }
1190  html_form('edit', $form);
1191  print '</div>'.NL;
1192}
1193
1194/**
1195 * Adds a checkbox for minor edits for logged in users
1196 *
1197 * @author Andrea Gohr <andi@splitbrain.org>
1198 */
1199function html_minoredit(){
1200  global $conf;
1201  global $lang;
1202  // minor edits are for logged in users only
1203  if(!$conf['useacl'] || !$_SERVER['REMOTE_USER']){
1204    return false;
1205  }
1206
1207  $p = array();
1208  $p['tabindex'] = 3;
1209  if(!empty($_REQUEST['minor'])) $p['checked']='checked';
1210  return form_makeCheckboxField('minor', '1', $lang['minoredit'], 'minoredit', 'nowrap', $p);
1211}
1212
1213/**
1214 * prints some debug info
1215 *
1216 * @author Andreas Gohr <andi@splitbrain.org>
1217 */
1218function html_debug(){
1219  global $conf;
1220  global $lang;
1221  global $auth;
1222  global $INFO;
1223
1224  //remove sensitive data
1225  $cnf = $conf;
1226  debug_guard($cnf);
1227  $nfo = $INFO;
1228  debug_guard($nfo);
1229  $ses = $_SESSION;
1230  debug_guard($ses);
1231
1232  print '<html><body>';
1233
1234  print '<p>When reporting bugs please send all the following ';
1235  print 'output as a mail to andi@splitbrain.org ';
1236  print 'The best way to do this is to save this page in your browser</p>';
1237
1238  print '<b>$INFO:</b><pre>';
1239  print_r($nfo);
1240  print '</pre>';
1241
1242  print '<b>$_SERVER:</b><pre>';
1243  print_r($_SERVER);
1244  print '</pre>';
1245
1246  print '<b>$conf:</b><pre>';
1247  print_r($cnf);
1248  print '</pre>';
1249
1250  print '<b>DOKU_BASE:</b><pre>';
1251  print DOKU_BASE;
1252  print '</pre>';
1253
1254  print '<b>abs DOKU_BASE:</b><pre>';
1255  print DOKU_URL;
1256  print '</pre>';
1257
1258  print '<b>rel DOKU_BASE:</b><pre>';
1259  print dirname($_SERVER['PHP_SELF']).'/';
1260  print '</pre>';
1261
1262  print '<b>PHP Version:</b><pre>';
1263  print phpversion();
1264  print '</pre>';
1265
1266  print '<b>locale:</b><pre>';
1267  print setlocale(LC_ALL,0);
1268  print '</pre>';
1269
1270  print '<b>encoding:</b><pre>';
1271  print $lang['encoding'];
1272  print '</pre>';
1273
1274  if($auth){
1275    print '<b>Auth backend capabilities:</b><pre>';
1276    print_r($auth->cando);
1277    print '</pre>';
1278  }
1279
1280  print '<b>$_SESSION:</b><pre>';
1281  print_r($ses);
1282  print '</pre>';
1283
1284  print '<b>Environment:</b><pre>';
1285  print_r($_ENV);
1286  print '</pre>';
1287
1288  print '<b>PHP settings:</b><pre>';
1289  $inis = ini_get_all();
1290  print_r($inis);
1291  print '</pre>';
1292
1293  print '</body></html>';
1294}
1295
1296function html_admin(){
1297  global $ID;
1298  global $INFO;
1299  global $lang;
1300  global $conf;
1301
1302  print p_locale_xhtml('admin');
1303
1304  // build menu of admin functions from the plugins that handle them
1305  $pluginlist = plugin_list('admin');
1306  $menu = array();
1307  foreach ($pluginlist as $p) {
1308    if($obj =& plugin_load('admin',$p) === NULL) continue;
1309
1310    // check permissions
1311    if($obj->forAdminOnly() && !$INFO['isadmin']) continue;
1312
1313    $menu[] = array('plugin' => $p,
1314                    'prompt' => $obj->getMenuText($conf['lang']),
1315                    'sort' => $obj->getMenuSort()
1316                   );
1317  }
1318
1319  usort($menu, 'p_sort_modes');
1320
1321  // output the menu
1322  ptln('<ul>');
1323
1324  foreach ($menu as $item) {
1325    if (!$item['prompt']) continue;
1326    ptln('  <li><div class="li"><a href="'.wl($ID, 'do=admin&amp;page='.$item['plugin']).'">'.$item['prompt'].'</a></div></li>');
1327  }
1328
1329  ptln('</ul>');
1330}
1331
1332/**
1333 * Form to request a new password for an existing account
1334 *
1335 * @author Benoit Chesneau <benoit@bchesneau.info>
1336 */
1337function html_resendpwd() {
1338  global $lang;
1339  global $conf;
1340  global $ID;
1341
1342  print p_locale_xhtml('resendpwd');
1343  print '<div class="centeralign">'.NL;
1344  $form = new Doku_Form('dw__resendpwd', wl($ID));
1345  $form->startFieldset($lang['resendpwd']);
1346  $form->addHidden('do', 'resendpwd');
1347  $form->addHidden('save', '1');
1348  $form->addElement(form_makeTag('br'));
1349  $form->addElement(form_makeTextField('login', $_POST['login'], $lang['user'], '', 'block'));
1350  $form->addElement(form_makeTag('br'));
1351  $form->addElement(form_makeTag('br'));
1352  $form->addElement(form_makeButton('submit', '', $lang['btn_resendpwd']));
1353  $form->endFieldset();
1354  html_form('resendpwd', $form);
1355  print '</div>'.NL;
1356}
1357
1358/**
1359 * Return the TOC rendered to XHTML
1360 *
1361 * @author Andreas Gohr <andi@splitbrain.org>
1362 */
1363function html_TOC($toc){
1364    if(!count($toc)) return '';
1365    global $lang;
1366    $out  = '<!-- TOC START -->'.DOKU_LF;
1367    $out .= '<div class="toc">'.DOKU_LF;
1368    $out .= '<div class="tocheader toctoggle" id="toc__header">';
1369    $out .= $lang['toc'];
1370    $out .= '</div>'.DOKU_LF;
1371    $out .= '<div id="toc__inside">'.DOKU_LF;
1372    $out .= html_buildlist($toc,'toc','html_list_toc');
1373    $out .= '</div>'.DOKU_LF.'</div>'.DOKU_LF;
1374    $out .= '<!-- TOC END -->'.DOKU_LF;
1375    return $out;                                                                                                }
1376
1377/**
1378 * Callback for html_buildlist
1379 */
1380function html_list_toc($item){
1381    if($item['hid']){
1382        $link = '#'.$item['hid'];
1383    }else{
1384        $link = $item['link'];
1385    }
1386
1387    return '<span class="li"><a href="'.$link.'" class="toc">'.
1388           hsc($item['title']).'</a></span>';
1389}
1390
1391/**
1392 * Helper function to build TOC items
1393 *
1394 * Returns an array ready to be added to a TOC array
1395 *
1396 * @param string $link  - where to link (if $hash set to '#' it's a local anchor)
1397 * @param string $text  - what to display in the TOC
1398 * @param int    $level - nesting level
1399 * @param string $hash  - is prepended to the given $link, set blank if you want full links
1400 */
1401function html_mktocitem($link, $text, $level, $hash='#'){
1402    global $conf;
1403    return  array( 'link'  => $hash.$link,
1404                   'title' => $text,
1405                   'type'  => 'ul',
1406                   'level' => $level);
1407}
1408
1409/**
1410 * Output a Doku_Form object.
1411 * Triggers an event with the form name: HTML_{$name}FORM_OUTPUT
1412 *
1413 * @author Tom N Harris <tnharris@whoopdedo.org>
1414 */
1415function html_form($name, &$form) {
1416  // Safety check in case the caller forgets.
1417  $form->endFieldset();
1418  trigger_event('HTML_'.strtoupper($name).'FORM_OUTPUT', $form, 'html_form_output', false);
1419}
1420
1421/**
1422 * Form print function.
1423 * Just calls printForm() on the data object.
1424 */
1425function html_form_output($data) {
1426  $data->printForm();
1427}
1428
1429//Setup VIM: ex: et ts=2 enc=utf-8 :
1430