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