[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ -> form.php (source)

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