xref: /dokuwiki/inc/form.php (revision 1de6f5c9063eaf6eda4e88702b2e2cdeb59ea652)
1<?php
2/**
3 * DokuWiki XHTML Form
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Tom N Harris <tnharris@whoopdedo.org>
7 */
8
9if(!defined('DOKU_INC')) die('meh.');
10
11/**
12 * Class for creating simple HTML forms.
13 *
14 * The forms is built from a list of pseudo-tags (arrays with expected keys).
15 * Every pseudo-tag must have the key '_elem' set to the name of the element.
16 * When printed, the form class calls functions named 'form_$type' for each
17 * element it contains.
18 *
19 * Standard practice is for non-attribute keys in a pseudo-element to start
20 * with '_'. Other keys are HTML attributes that will be included in the element
21 * tag. That way, the element output functions can pass the pseudo-element
22 * directly to buildAttributes.
23 *
24 * See the form_make* functions later in this file.
25 *
26 * @author Tom N Harris <tnharris@whoopdedo.org>
27 */
28class Doku_Form {
29
30    // Form id attribute
31    public $params = array();
32
33    // Draw a border around form fields.
34    // Adds <fieldset></fieldset> around the elements
35    public $_infieldset = false;
36
37    // Hidden form fields.
38    public $_hidden = array();
39
40    // Array of pseudo-tags
41    public $_content = array();
42
43    /**
44     * Constructor
45     *
46     * Sets parameters and autoadds a security token. The old calling convention
47     * with up to four parameters is deprecated, instead the first parameter
48     * should be an array with parameters.
49     *
50     * @param mixed       $params  Parameters for the HTML form element; Using the deprecated
51     *                             calling convention this is the ID attribute of the form
52     * @param bool|string $action  (optional, deprecated) submit URL, defaults to current page
53     * @param bool|string $method  (optional, deprecated) 'POST' or 'GET', default is POST
54     * @param bool|string $enctype (optional, deprecated) Encoding type of the data
55     *
56     * @author  Tom N Harris <tnharris@whoopdedo.org>
57     */
58    function __construct($params, $action=false, $method=false, $enctype=false) {
59        if(!is_array($params)) {
60            $this->params = array('id' => $params);
61            if ($action !== false) $this->params['action'] = $action;
62            if ($method !== false) $this->params['method'] = strtolower($method);
63            if ($enctype !== false) $this->params['enctype'] = $enctype;
64        } else {
65            $this->params = $params;
66        }
67
68        if (!isset($this->params['method'])) {
69            $this->params['method'] = 'post';
70        } else {
71            $this->params['method'] = strtolower($this->params['method']);
72        }
73
74        if (!isset($this->params['action'])) {
75            $this->params['action'] = '';
76        }
77
78        $this->addHidden('sectok', getSecurityToken());
79    }
80
81    /**
82     * startFieldset
83     *
84     * Add <fieldset></fieldset> tags around fields.
85     * Usually results in a border drawn around the form.
86     *
87     * @param   string  $legend Label that will be printed with the border.
88     *
89     * @author  Tom N Harris <tnharris@whoopdedo.org>
90     */
91    function startFieldset($legend) {
92        if ($this->_infieldset) {
93            $this->addElement(array('_elem'=>'closefieldset'));
94        }
95        $this->addElement(array('_elem'=>'openfieldset', '_legend'=>$legend));
96        $this->_infieldset = true;
97    }
98
99    /**
100     * endFieldset
101     *
102     * @author  Tom N Harris <tnharris@whoopdedo.org>
103     */
104    function endFieldset() {
105        if ($this->_infieldset) {
106            $this->addElement(array('_elem'=>'closefieldset'));
107        }
108        $this->_infieldset = false;
109    }
110
111    /**
112     * addHidden
113     *
114     * Adds a name/value pair as a hidden field.
115     * The value of the field (but not the name) will be passed to
116     * formText() before printing.
117     *
118     * @param   string  $name   Field name.
119     * @param   string  $value  Field value. If null, remove a previously added field.
120     *
121     * @author  Tom N Harris <tnharris@whoopdedo.org>
122     */
123    function addHidden($name, $value) {
124        if (is_null($value))
125            unset($this->_hidden[$name]);
126        else
127            $this->_hidden[$name] = $value;
128    }
129
130    /**
131     * addElement
132     *
133     * Appends a content element to the form.
134     * The element can be either a pseudo-tag or string.
135     * If string, it is printed without escaping special chars.   *
136     *
137     * @param   string|array  $elem   Pseudo-tag or string to add to the form.
138     *
139     * @author  Tom N Harris <tnharris@whoopdedo.org>
140     */
141    function addElement($elem) {
142        $this->_content[] = $elem;
143    }
144
145    /**
146     * insertElement
147     *
148     * Inserts a content element at a position.
149     *
150     * @param   string       $pos  0-based index where the element will be inserted.
151     * @param   string|array $elem Pseudo-tag or string to add to the form.
152     *
153     * @author  Tom N Harris <tnharris@whoopdedo.org>
154     */
155    function insertElement($pos, $elem) {
156        array_splice($this->_content, $pos, 0, array($elem));
157    }
158
159    /**
160     * replaceElement
161     *
162     * Replace with NULL to remove an element.
163     *
164     * @param   int          $pos  0-based index the element will be placed at.
165     * @param   string|array $elem Pseudo-tag or string to add to the form.
166     *
167     * @author  Tom N Harris <tnharris@whoopdedo.org>
168     */
169    function replaceElement($pos, $elem) {
170        $rep = array();
171        if (!is_null($elem)) $rep[] = $elem;
172        array_splice($this->_content, $pos, 1, $rep);
173    }
174
175    /**
176     * findElementByType
177     *
178     * Gets the position of the first of a type of element.
179     *
180     * @param   string  $type   Element type to look for.
181     * @return  int|false     position of element if found, otherwise false
182     *
183     * @author  Tom N Harris <tnharris@whoopdedo.org>
184     */
185    function findElementByType($type) {
186        foreach ($this->_content as $pos=>$elem) {
187            if (is_array($elem) && $elem['_elem'] == $type)
188                return $pos;
189        }
190        return false;
191    }
192
193    /**
194     * findElementById
195     *
196     * Gets the position of the element with an ID attribute.
197     *
198     * @param   string  $id     ID of the element to find.
199     * @return  int|false     position of element if found, otherwise false
200     *
201     * @author  Tom N Harris <tnharris@whoopdedo.org>
202     */
203    function findElementById($id) {
204        foreach ($this->_content as $pos=>$elem) {
205            if (is_array($elem) && isset($elem['id']) && $elem['id'] == $id)
206                return $pos;
207        }
208        return false;
209    }
210
211    /**
212     * findElementByAttribute
213     *
214     * Gets the position of the first element with a matching attribute value.
215     *
216     * @param   string  $name   Attribute name.
217     * @param   string  $value  Attribute value.
218     * @return  int|false     position of element if found, otherwise false
219     *
220     * @author  Tom N Harris <tnharris@whoopdedo.org>
221     */
222    function findElementByAttribute($name, $value) {
223        foreach ($this->_content as $pos=>$elem) {
224            if (is_array($elem) && isset($elem[$name]) && $elem[$name] == $value)
225                return $pos;
226        }
227        return false;
228    }
229
230    /**
231     * getElementAt
232     *
233     * Returns a reference to the element at a position.
234     * A position out-of-bounds will return either the
235     * first (underflow) or last (overflow) element.
236     *
237     * @param   int     $pos    0-based index
238     * @return  array reference  pseudo-element
239     *
240     * @author  Tom N Harris <tnharris@whoopdedo.org>
241     */
242    function &getElementAt($pos) {
243        if ($pos < 0) $pos = count($this->_content) + $pos;
244        if ($pos < 0) $pos = 0;
245        if ($pos >= count($this->_content)) $pos = count($this->_content) - 1;
246        return $this->_content[$pos];
247    }
248
249    /**
250     * Return the assembled HTML for the form.
251     *
252     * Each element in the form will be passed to a function named
253     * 'form_$type'. The function should return the HTML to be printed.
254     *
255     * @author  Tom N Harris <tnharris@whoopdedo.org>
256     *
257     * @return string html of the form
258     */
259    function getForm() {
260        global $lang;
261        $form = '';
262        $this->params['accept-charset'] = $lang['encoding'];
263        $form .= '<form ' . buildAttributes($this->params,false) . '><div class="no">' . DOKU_LF;
264        if (!empty($this->_hidden)) {
265            foreach ($this->_hidden as $name=>$value)
266                $form .= form_hidden(array('name'=>$name, 'value'=>$value));
267        }
268        foreach ($this->_content as $element) {
269            if (is_array($element)) {
270                $elem_type = $element['_elem'];
271                if (function_exists('form_'.$elem_type)) {
272                    $form .= call_user_func('form_'.$elem_type, $element).DOKU_LF;
273                }
274            } else {
275                $form .= $element;
276            }
277        }
278        if ($this->_infieldset) $form .= form_closefieldset().DOKU_LF;
279        $form .= '</div></form>'.DOKU_LF;
280
281        return $form;
282    }
283
284    /**
285     * Print the assembled form
286     *
287     * wraps around getForm()
288     */
289    function printForm(){
290        echo $this->getForm();
291    }
292
293    /**
294     * Add a radio set
295     *
296     * This function adds a set of radio buttons to the form. If $_POST[$name]
297     * is set, this radio is preselected, else the first radio button.
298     *
299     * @param string    $name    The HTML field name
300     * @param array     $entries An array of entries $value => $caption
301     *
302     * @author Adrian Lang <lang@cosmocode.de>
303     */
304
305    function addRadioSet($name, $entries) {
306        global $INPUT;
307        $value = (array_key_exists($INPUT->post->str($name), $entries)) ?
308                 $INPUT->str($name) : key($entries);
309        foreach($entries as $val => $cap) {
310            $data = ($value === $val) ? array('checked' => 'checked') : array();
311            $this->addElement(form_makeRadioField($name, $val, $cap, '', '', $data));
312        }
313    }
314
315}
316
317/**
318 * form_makeTag
319 *
320 * Create a form element for a non-specific empty tag.
321 *
322 * @param   string  $tag    Tag name.
323 * @param   array   $attrs  Optional attributes.
324 * @return  array   pseudo-tag
325 *
326 * @author  Tom N Harris <tnharris@whoopdedo.org>
327 */
328function form_makeTag($tag, $attrs=array()) {
329    $elem = array('_elem'=>'tag', '_tag'=>$tag);
330    return array_merge($elem, $attrs);
331}
332
333/**
334 * form_makeOpenTag
335 *
336 * Create a form element for a non-specific opening tag.
337 * Remember to put a matching close tag after this as well.
338 *
339 * @param   string  $tag    Tag name.
340 * @param   array   $attrs  Optional attributes.
341 * @return  array   pseudo-tag
342 *
343 * @author  Tom N Harris <tnharris@whoopdedo.org>
344 */
345function form_makeOpenTag($tag, $attrs=array()) {
346    $elem = array('_elem'=>'opentag', '_tag'=>$tag);
347    return array_merge($elem, $attrs);
348}
349
350/**
351 * form_makeCloseTag
352 *
353 * Create a form element for a non-specific closing tag.
354 * Careless use of this will result in invalid XHTML.
355 *
356 * @param   string  $tag    Tag name.
357 * @return  array   pseudo-tag
358 *
359 * @author  Tom N Harris <tnharris@whoopdedo.org>
360 */
361function form_makeCloseTag($tag) {
362    return array('_elem'=>'closetag', '_tag'=>$tag);
363}
364
365/**
366 * form_makeWikiText
367 *
368 * Create a form element for a textarea containing wiki text.
369 * Only one wikitext element is allowed on a page. It will have
370 * a name of 'wikitext' and id 'wiki__text'. The text will
371 * be passed to formText() before printing.
372 *
373 * @param   string  $text   Text to fill the field with.
374 * @param   array   $attrs  Optional attributes.
375 * @return  array   pseudo-tag
376 *
377 * @author  Tom N Harris <tnharris@whoopdedo.org>
378 */
379function form_makeWikiText($text, $attrs=array()) {
380    $elem = array('_elem'=>'wikitext', '_text'=>$text,
381                        'class'=>'edit', 'cols'=>'80', 'rows'=>'10');
382    return array_merge($elem, $attrs);
383}
384
385/**
386 * form_makeButton
387 *
388 * Create a form element for an action button.
389 * A title will automatically be generated using the value and
390 * accesskey attributes, unless you provide one.
391 *
392 * @param   string  $type   Type attribute. 'submit' or 'cancel'
393 * @param   string  $act    Wiki action of the button, will be used as the do= parameter
394 * @param   string  $value  (optional) Displayed label. Uses $act if not provided.
395 * @param   array   $attrs  Optional attributes.
396 * @return  array   pseudo-tag
397 *
398 * @author  Tom N Harris <tnharris@whoopdedo.org>
399 */
400function form_makeButton($type, $act, $value='', $attrs=array()) {
401    if ($value == '') $value = $act;
402    $elem = array('_elem'=>'button', 'type'=>$type, '_action'=>$act,
403                        'value'=>$value);
404    if (!empty($attrs['accesskey']) && empty($attrs['title'])) {
405        $attrs['title'] = $value . ' ['.strtoupper($attrs['accesskey']).']';
406    }
407    return array_merge($elem, $attrs);
408}
409
410/**
411 * form_makeField
412 *
413 * Create a form element for a labelled input element.
414 * The label text will be printed before the input.
415 *
416 * @param   string  $type   Type attribute of input.
417 * @param   string  $name   Name attribute of the input.
418 * @param   string  $value  (optional) Default value.
419 * @param   string  $class  Class attribute of the label. If this is 'block',
420 *                          then a line break will be added after the field.
421 * @param   string  $label  Label that will be printed before the input.
422 * @param   string  $id     ID attribute of the input. If set, the label will
423 *                          reference it with a 'for' attribute.
424 * @param   array   $attrs  Optional attributes.
425 * @return  array   pseudo-tag
426 *
427 * @author  Tom N Harris <tnharris@whoopdedo.org>
428 */
429function form_makeField($type, $name, $value='', $label=null, $id='', $class='', $attrs=array()) {
430    if (is_null($label)) $label = $name;
431    $elem = array('_elem'=>'field', '_text'=>$label, '_class'=>$class,
432                        'type'=>$type, 'id'=>$id, 'name'=>$name, 'value'=>$value);
433    return array_merge($elem, $attrs);
434}
435
436/**
437 * form_makeFieldRight
438 *
439 * Create a form element for a labelled input element.
440 * The label text will be printed after the input.
441 *
442 * @see     form_makeField
443 * @author  Tom N Harris <tnharris@whoopdedo.org>
444 *
445 * @param string $type
446 * @param string $name
447 * @param string $value
448 * @param null|string $label
449 * @param string $id
450 * @param string $class
451 * @param array $attrs
452 *
453 * @return array
454 */
455function form_makeFieldRight($type, $name, $value='', $label=null, $id='', $class='', $attrs=array()) {
456    if (is_null($label)) $label = $name;
457    $elem = array('_elem'=>'fieldright', '_text'=>$label, '_class'=>$class,
458                        'type'=>$type, 'id'=>$id, 'name'=>$name, 'value'=>$value);
459    return array_merge($elem, $attrs);
460}
461
462/**
463 * form_makeTextField
464 *
465 * Create a form element for a text input element with label.
466 *
467 * @see     form_makeField
468 * @author  Tom N Harris <tnharris@whoopdedo.org>
469 *
470 * @param string $name
471 * @param string $value
472 * @param null|string $label
473 * @param string $id
474 * @param string $class
475 * @param array $attrs
476 *
477 * @return array
478 */
479function form_makeTextField($name, $value='', $label=null, $id='', $class='', $attrs=array()) {
480    if (is_null($label)) $label = $name;
481    $elem = array('_elem'=>'textfield', '_text'=>$label, '_class'=>$class,
482                        'id'=>$id, 'name'=>$name, 'value'=>$value, 'class'=>'edit');
483    return array_merge($elem, $attrs);
484}
485
486/**
487 * form_makePasswordField
488 *
489 * Create a form element for a password input element with label.
490 * Password elements have no default value, for obvious reasons.
491 *
492 * @see     form_makeField
493 * @author  Tom N Harris <tnharris@whoopdedo.org>
494 *
495 * @param string $name
496 * @param null|string $label
497 * @param string $id
498 * @param string $class
499 * @param array $attrs
500 *
501 * @return array
502 */
503function form_makePasswordField($name, $label=null, $id='', $class='', $attrs=array()) {
504    if (is_null($label)) $label = $name;
505    $elem = array('_elem'=>'passwordfield', '_text'=>$label, '_class'=>$class,
506                        'id'=>$id, 'name'=>$name, 'class'=>'edit');
507    return array_merge($elem, $attrs);
508}
509
510/**
511 * form_makeFileField
512 *
513 * Create a form element for a file input element with label
514 *
515 * @see     form_makeField
516 * @author  Michael Klier <chi@chimeric.de>
517 *
518 * @param string $name
519 * @param null|string $label
520 * @param string $id
521 * @param string $class
522 * @param array $attrs
523 *
524 * @return array
525 */
526function form_makeFileField($name, $label=null, $id='', $class='', $attrs=array()) {
527    if (is_null($label)) $label = $name;
528    $elem = array('_elem'=>'filefield', '_text'=>$label, '_class'=>$class,
529                        'id'=>$id, 'name'=>$name, 'class'=>'edit');
530    return array_merge($elem, $attrs);
531}
532
533/**
534 * form_makeCheckboxField
535 *
536 * Create a form element for a checkbox input element with label.
537 * If $value is an array, a hidden field with the same name and the value
538 * $value[1] is constructed as well.
539 *
540 * @see     form_makeFieldRight
541 * @author  Tom N Harris <tnharris@whoopdedo.org>
542 *
543 * @param string $name
544 * @param string $value
545 * @param null|string $label
546 * @param string $id
547 * @param string $class
548 * @param array $attrs
549 *
550 * @return array
551 */
552function form_makeCheckboxField($name, $value='1', $label=null, $id='', $class='', $attrs=array()) {
553    if (is_null($label)) $label = $name;
554    if (is_null($value) || $value=='') $value='0';
555    $elem = array('_elem'=>'checkboxfield', '_text'=>$label, '_class'=>$class,
556                        'id'=>$id, 'name'=>$name, 'value'=>$value);
557    return array_merge($elem, $attrs);
558}
559
560/**
561 * form_makeRadioField
562 *
563 * Create a form element for a radio button input element with label.
564 *
565 * @see     form_makeFieldRight
566 * @author  Tom N Harris <tnharris@whoopdedo.org>
567 *
568 * @param string $name
569 * @param string $value
570 * @param null|string $label
571 * @param string $id
572 * @param string $class
573 * @param array $attrs
574 *
575 * @return array
576 */
577function form_makeRadioField($name, $value='1', $label=null, $id='', $class='', $attrs=array()) {
578    if (is_null($label)) $label = $name;
579    if (is_null($value) || $value=='') $value='0';
580    $elem = array('_elem'=>'radiofield', '_text'=>$label, '_class'=>$class,
581                        'id'=>$id, 'name'=>$name, 'value'=>$value);
582    return array_merge($elem, $attrs);
583}
584
585/**
586 * form_makeMenuField
587 *
588 * Create a form element for a drop-down menu with label.
589 * The list of values can be strings, arrays of (value,text),
590 * or an associative array with the values as keys and labels as values.
591 * An item is selected by supplying its value or integer index.
592 * If the list of values is an associative array, the selected item must be
593 * a string.
594 *
595 * @author  Tom N Harris <tnharris@whoopdedo.org>
596 *
597 * @param string           $name     Name attribute of the input.
598 * @param string[]|array[] $values   The list of values can be strings, arrays of (value,text),
599 *                                   or an associative array with the values as keys and labels as values.
600 * @param string|int       $selected default selected value, string or index number
601 * @param string           $class    Class attribute of the label. If this is 'block',
602 *                                   then a line break will be added after the field.
603 * @param string           $label    Label that will be printed before the input.
604 * @param string           $id       ID attribute of the input. If set, the label will
605 *                                   reference it with a 'for' attribute.
606 * @param array            $attrs    Optional attributes.
607 * @return array   pseudo-tag
608 */
609function form_makeMenuField($name, $values, $selected='', $label=null, $id='', $class='', $attrs=array()) {
610    if (is_null($label)) $label = $name;
611    $options = array();
612    reset($values);
613    // FIXME: php doesn't know the difference between a string and an integer
614    if (is_string(key($values))) {
615        foreach ($values as $val=>$text) {
616            $options[] = array($val,$text, (!is_null($selected) && $val==$selected));
617        }
618    } else {
619        if (is_integer($selected)) $selected = $values[$selected];
620        foreach ($values as $val) {
621            if (is_array($val))
622                @list($val,$text) = $val;
623            else
624                $text = null;
625            $options[] = array($val,$text,$val===$selected);
626        }
627    }
628    $elem = array('_elem'=>'menufield', '_options'=>$options, '_text'=>$label, '_class'=>$class,
629                        'id'=>$id, 'name'=>$name);
630    return array_merge($elem, $attrs);
631}
632
633/**
634 * form_makeListboxField
635 *
636 * Create a form element for a list box with label.
637 * The list of values can be strings, arrays of (value,text),
638 * or an associative array with the values as keys and labels as values.
639 * Items are selected by supplying its value or an array of values.
640 *
641 * @author  Tom N Harris <tnharris@whoopdedo.org>
642 *
643 * @param string           $name     Name attribute of the input.
644 * @param string[]|array[] $values   The list of values can be strings, arrays of (value,text),
645 *                                   or an associative array with the values as keys and labels as values.
646 * @param array|string     $selected value or array of values of the items that need to be selected
647 * @param string           $class    Class attribute of the label. If this is 'block',
648 *                                   then a line break will be added after the field.
649 * @param string           $label    Label that will be printed before the input.
650 * @param string           $id       ID attribute of the input. If set, the label will
651 *                                   reference it with a 'for' attribute.
652 * @param array            $attrs    Optional attributes.
653 * @return array   pseudo-tag
654 */
655function form_makeListboxField($name, $values, $selected='', $label=null, $id='', $class='', $attrs=array()) {
656    if (is_null($label)) $label = $name;
657    $options = array();
658    reset($values);
659    if (is_null($selected) || $selected == '') {
660        $selected = array();
661    } elseif (!is_array($selected)) {
662        $selected = array($selected);
663    }
664    // FIXME: php doesn't know the difference between a string and an integer
665    if (is_string(key($values))) {
666        foreach ($values as $val=>$text) {
667            $options[] = array($val,$text,in_array($val,$selected));
668        }
669    } else {
670        foreach ($values as $val) {
671            $disabled = false;
672            if (is_array($val)) {
673                @list($val,$text,$disabled) = $val;
674            } else {
675                $text = null;
676            }
677            $options[] = array($val,$text,in_array($val,$selected),$disabled);
678        }
679    }
680    $elem = array('_elem'=>'listboxfield', '_options'=>$options, '_text'=>$label, '_class'=>$class,
681                        'id'=>$id, 'name'=>$name);
682    return array_merge($elem, $attrs);
683}
684
685/**
686 * form_tag
687 *
688 * Print the HTML for a generic empty tag.
689 * Requires '_tag' key with name of the tag.
690 * Attributes are passed to buildAttributes()
691 *
692 * @author  Tom N Harris <tnharris@whoopdedo.org>
693 *
694 * @param array $attrs attributes
695 * @return string html of tag
696 */
697function form_tag($attrs) {
698    return '<'.$attrs['_tag'].' '.buildAttributes($attrs,true).'/>';
699}
700
701/**
702 * form_opentag
703 *
704 * Print the HTML for a generic opening tag.
705 * Requires '_tag' key with name of the tag.
706 * Attributes are passed to buildAttributes()
707 *
708 * @author  Tom N Harris <tnharris@whoopdedo.org>
709 *
710 * @param array $attrs attributes
711 * @return string html of tag
712 */
713function form_opentag($attrs) {
714    return '<'.$attrs['_tag'].' '.buildAttributes($attrs,true).'>';
715}
716
717/**
718 * form_closetag
719 *
720 * Print the HTML for a generic closing tag.
721 * Requires '_tag' key with name of the tag.
722 * There are no attributes.
723 *
724 * @author  Tom N Harris <tnharris@whoopdedo.org>
725 *
726 * @param array $attrs attributes
727 * @return string html of tag
728 */
729function form_closetag($attrs) {
730    return '</'.$attrs['_tag'].'>';
731}
732
733/**
734 * form_openfieldset
735 *
736 * Print the HTML for an opening fieldset tag.
737 * Uses the '_legend' key.
738 * Attributes are passed to buildAttributes()
739 *
740 * @author  Tom N Harris <tnharris@whoopdedo.org>
741 *
742 * @param array $attrs attributes
743 * @return string html
744 */
745function form_openfieldset($attrs) {
746    $s = '<fieldset '.buildAttributes($attrs,true).'>';
747    if (!is_null($attrs['_legend'])) $s .= '<legend>'.$attrs['_legend'].'</legend>';
748    return $s;
749}
750
751/**
752 * form_closefieldset
753 *
754 * Print the HTML for a closing fieldset tag.
755 * There are no attributes.
756 *
757 * @author  Tom N Harris <tnharris@whoopdedo.org>
758 *
759 * @return string html
760 */
761function form_closefieldset() {
762    return '</fieldset>';
763}
764
765/**
766 * form_hidden
767 *
768 * Print the HTML for a hidden input element.
769 * Uses only 'name' and 'value' attributes.
770 * Value is passed to formText()
771 *
772 * @author  Tom N Harris <tnharris@whoopdedo.org>
773 *
774 * @param array $attrs attributes
775 * @return string html
776 */
777function form_hidden($attrs) {
778    return '<input type="hidden" name="'.$attrs['name'].'" value="'.formText($attrs['value']).'" />';
779}
780
781/**
782 * form_wikitext
783 *
784 * Print the HTML for the wiki textarea.
785 * Requires '_text' with default text of the field.
786 * Text will be passed to formText(), attributes to buildAttributes()
787 *
788 * @author  Tom N Harris <tnharris@whoopdedo.org>
789 *
790 * @param array $attrs attributes
791 * @return string html
792 */
793function form_wikitext($attrs) {
794    // mandatory attributes
795    unset($attrs['name']);
796    unset($attrs['id']);
797    return '<textarea name="wikitext" id="wiki__text" dir="auto" '
798                 .buildAttributes($attrs,true).'>'.DOKU_LF
799                 .formText($attrs['_text'])
800                 .'</textarea>';
801}
802
803/**
804 * form_button
805 *
806 * Print the HTML for a form button.
807 * If '_action' is set, the button name will be "do[_action]".
808 * Other attributes are passed to buildAttributes()
809 *
810 * @author  Tom N Harris <tnharris@whoopdedo.org>
811 *
812 * @param array $attrs attributes
813 * @return string html
814 */
815function form_button($attrs) {
816    $p = (!empty($attrs['_action'])) ? 'name="do['.$attrs['_action'].']" ' : '';
817    $value = $attrs['value'];
818    unset($attrs['value']);
819    return '<button '.$p.buildAttributes($attrs,true).'>'.$value.'</button>';
820}
821
822/**
823 * form_field
824 *
825 * Print the HTML for a form input field.
826 *   _class : class attribute used on the label tag
827 *   _text  : Text to display before the input. Not escaped.
828 * Other attributes are passed to buildAttributes() for the input tag.
829 *
830 * @author  Tom N Harris <tnharris@whoopdedo.org>
831 *
832 * @param array $attrs attributes
833 * @return string html
834 */
835function form_field($attrs) {
836    $s = '<label';
837    if ($attrs['_class']) $s .= ' class="'.$attrs['_class'].'"';
838    if (!empty($attrs['id'])) $s .= ' for="'.$attrs['id'].'"';
839    $s .= '><span>'.$attrs['_text'].'</span>';
840    $s .= ' <input '.buildAttributes($attrs,true).' /></label>';
841    if (preg_match('/(^| )block($| )/', $attrs['_class']))
842        $s .= '<br />';
843    return $s;
844}
845
846/**
847 * form_fieldright
848 *
849 * Print the HTML for a form input field. (right-aligned)
850 *   _class : class attribute used on the label tag
851 *   _text  : Text to display after the input. Not escaped.
852 * Other attributes are passed to buildAttributes() for the input tag.
853 *
854 * @author  Tom N Harris <tnharris@whoopdedo.org>
855 *
856 * @param array $attrs attributes
857 * @return string html
858 */
859function form_fieldright($attrs) {
860    $s = '<label';
861    if ($attrs['_class']) $s .= ' class="'.$attrs['_class'].'"';
862    if (!empty($attrs['id'])) $s .= ' for="'.$attrs['id'].'"';
863    $s .= '><input '.buildAttributes($attrs,true).' />';
864    $s .= ' <span>'.$attrs['_text'].'</span></label>';
865    if (preg_match('/(^| )block($| )/', $attrs['_class']))
866        $s .= '<br />';
867    return $s;
868}
869
870/**
871 * form_textfield
872 *
873 * Print the HTML for a text input field.
874 *   _class : class attribute used on the label tag
875 *   _text  : Text to display before the input. Not escaped.
876 * Other attributes are passed to buildAttributes() for the input tag.
877 *
878 * @author  Tom N Harris <tnharris@whoopdedo.org>
879 *
880 * @param array $attrs attributes
881 * @return string html
882 */
883function form_textfield($attrs) {
884    // mandatory attributes
885    unset($attrs['type']);
886    $s = '<label';
887    if ($attrs['_class']) $s .= ' class="'.$attrs['_class'].'"';
888    if (!empty($attrs['id'])) $s .= ' for="'.$attrs['id'].'"';
889    $s .= '><span>'.$attrs['_text'].'</span> ';
890    $s .= '<input type="text" '.buildAttributes($attrs,true).' /></label>';
891    if (preg_match('/(^| )block($| )/', $attrs['_class']))
892        $s .= '<br />';
893    return $s;
894}
895
896/**
897 * form_passwordfield
898 *
899 * Print the HTML for a password input field.
900 *   _class : class attribute used on the label tag
901 *   _text  : Text to display before the input. Not escaped.
902 * Other attributes are passed to buildAttributes() for the input tag.
903 *
904 * @author  Tom N Harris <tnharris@whoopdedo.org>
905 *
906 * @param array $attrs attributes
907 * @return string html
908 */
909function form_passwordfield($attrs) {
910    // mandatory attributes
911    unset($attrs['type']);
912    $s = '<label';
913    if ($attrs['_class']) $s .= ' class="'.$attrs['_class'].'"';
914    if (!empty($attrs['id'])) $s .= ' for="'.$attrs['id'].'"';
915    $s .= '><span>'.$attrs['_text'].'</span> ';
916    $s .= '<input type="password" '.buildAttributes($attrs,true).' /></label>';
917    if (preg_match('/(^| )block($| )/', $attrs['_class']))
918        $s .= '<br />';
919    return $s;
920}
921
922/**
923 * form_filefield
924 *
925 * Print the HTML for a file input field.
926 *   _class     : class attribute used on the label tag
927 *   _text      : Text to display before the input. Not escaped
928 *   _maxlength : Allowed size in byte
929 *   _accept    : Accepted mime-type
930 * Other attributes are passed to buildAttributes() for the input tag
931 *
932 * @author  Michael Klier <chi@chimeric.de>
933 *
934 * @param array $attrs attributes
935 * @return string html
936 */
937function form_filefield($attrs) {
938    $s = '<label';
939    if ($attrs['_class']) $s .= ' class="'.$attrs['_class'].'"';
940    if (!empty($attrs['id'])) $s .= ' for="'.$attrs['id'].'"';
941    $s .= '><span>'.$attrs['_text'].'</span> ';
942    $s .= '<input type="file" '.buildAttributes($attrs,true);
943    if (!empty($attrs['_maxlength'])) $s .= ' maxlength="'.$attrs['_maxlength'].'"';
944    if (!empty($attrs['_accept'])) $s .= ' accept="'.$attrs['_accept'].'"';
945    $s .= ' /></label>';
946    if (preg_match('/(^| )block($| )/', $attrs['_class']))
947        $s .= '<br />';
948    return $s;
949}
950
951/**
952 * form_checkboxfield
953 *
954 * Print the HTML for a checkbox input field.
955 *   _class : class attribute used on the label tag
956 *   _text  : Text to display after the input. Not escaped.
957 * Other attributes are passed to buildAttributes() for the input tag.
958 * If value is an array, a hidden field with the same name and the value
959 * $attrs['value'][1] is constructed as well.
960 *
961 * @author  Tom N Harris <tnharris@whoopdedo.org>
962 *
963 * @param array $attrs attributes
964 * @return string html
965 */
966function form_checkboxfield($attrs) {
967    // mandatory attributes
968    unset($attrs['type']);
969    $s = '<label';
970    if ($attrs['_class']) $s .= ' class="'.$attrs['_class'].'"';
971    if (!empty($attrs['id'])) $s .= ' for="'.$attrs['id'].'"';
972    $s .= '>';
973    if (is_array($attrs['value'])) {
974        echo '<input type="hidden" name="' . hsc($attrs['name']) .'"'
975                 . ' value="' . hsc($attrs['value'][1]) . '" />';
976        $attrs['value'] = $attrs['value'][0];
977    }
978    $s .= '<input type="checkbox" '.buildAttributes($attrs,true).' />';
979    $s .= ' <span>'.$attrs['_text'].'</span></label>';
980    if (preg_match('/(^| )block($| )/', $attrs['_class']))
981        $s .= '<br />';
982    return $s;
983}
984
985/**
986 * form_radiofield
987 *
988 * Print the HTML for a radio button input field.
989 *   _class : class attribute used on the label tag
990 *   _text  : Text to display after the input. Not escaped.
991 * Other attributes are passed to buildAttributes() for the input tag.
992 *
993 * @author  Tom N Harris <tnharris@whoopdedo.org>
994 *
995 * @param array $attrs attributes
996 * @return string html
997 */
998function form_radiofield($attrs) {
999    // mandatory attributes
1000    unset($attrs['type']);
1001    $s = '<label';
1002    if ($attrs['_class']) $s .= ' class="'.$attrs['_class'].'"';
1003    if (!empty($attrs['id'])) $s .= ' for="'.$attrs['id'].'"';
1004    $s .= '><input type="radio" '.buildAttributes($attrs,true).' />';
1005    $s .= ' <span>'.$attrs['_text'].'</span></label>';
1006    if (preg_match('/(^| )block($| )/', $attrs['_class']))
1007        $s .= '<br />';
1008    return $s;
1009}
1010
1011/**
1012 * form_menufield
1013 *
1014 * Print the HTML for a drop-down menu.
1015 *   _options : Array of (value,text,selected) for the menu.
1016 *              Text can be omitted. Text and value are passed to formText()
1017 *              Only one item can be selected.
1018 *   _class : class attribute used on the label tag
1019 *   _text  : Text to display before the menu. Not escaped.
1020 * Other attributes are passed to buildAttributes() for the input tag.
1021 *
1022 * @author  Tom N Harris <tnharris@whoopdedo.org>
1023 *
1024 * @param array $attrs attributes
1025 * @return string html
1026 */
1027function form_menufield($attrs) {
1028    $attrs['size'] = '1';
1029    $s = '<label';
1030    if ($attrs['_class']) $s .= ' class="'.$attrs['_class'].'"';
1031    if (!empty($attrs['id'])) $s .= ' for="'.$attrs['id'].'"';
1032    $s .= '><span>'.$attrs['_text'].'</span>';
1033    $s .= ' <select '.buildAttributes($attrs,true).'>'.DOKU_LF;
1034    if (!empty($attrs['_options'])) {
1035        $selected = false;
1036
1037        $cnt = count($attrs['_options']);
1038        for($n=0; $n < $cnt; $n++){
1039            @list($value,$text,$select) = $attrs['_options'][$n];
1040            $p = '';
1041            if (!is_null($text))
1042                $p .= ' value="'.formText($value).'"';
1043            else
1044                $text = $value;
1045            if (!empty($select) && !$selected) {
1046                $p .= ' selected="selected"';
1047                $selected = true;
1048            }
1049            $s .= '<option'.$p.'>'.formText($text).'</option>';
1050        }
1051    } else {
1052        $s .= '<option></option>';
1053    }
1054    $s .= DOKU_LF.'</select></label>';
1055    if (preg_match('/(^| )block($| )/', $attrs['_class']))
1056        $s .= '<br />';
1057    return $s;
1058}
1059
1060/**
1061 * form_listboxfield
1062 *
1063 * Print the HTML for a list box.
1064 *   _options : Array of (value,text,selected) for the list.
1065 *              Text can be omitted. Text and value are passed to formText()
1066 *   _class : class attribute used on the label tag
1067 *   _text  : Text to display before the menu. Not escaped.
1068 * Other attributes are passed to buildAttributes() for the input tag.
1069 *
1070 * @author  Tom N Harris <tnharris@whoopdedo.org>
1071 *
1072 * @param array $attrs attributes
1073 * @return string html
1074 */
1075function form_listboxfield($attrs) {
1076    $s = '<label';
1077    if ($attrs['_class']) $s .= ' class="'.$attrs['_class'].'"';
1078    if (!empty($attrs['id'])) $s .= ' for="'.$attrs['id'].'"';
1079    $s .= '><span>'.$attrs['_text'].'</span> ';
1080    $s .= '<select '.buildAttributes($attrs,true).'>'.DOKU_LF;
1081    if (!empty($attrs['_options'])) {
1082        foreach ($attrs['_options'] as $opt) {
1083            @list($value,$text,$select,$disabled) = $opt;
1084            $p = '';
1085            if(is_null($text)) $text = $value;
1086            $p .= ' value="'.formText($value).'"';
1087            if (!empty($select)) $p .= ' selected="selected"';
1088            if ($disabled) $p .= ' disabled="disabled"';
1089            $s .= '<option'.$p.'>'.formText($text).'</option>';
1090        }
1091    } else {
1092        $s .= '<option></option>';
1093    }
1094    $s .= DOKU_LF.'</select></label>';
1095    if (preg_match('/(^| )block($| )/', $attrs['_class']))
1096        $s .= '<br />';
1097    return $s;
1098}
1099