[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ -> form.php (source)

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