1<?php 2namespace dokuwiki\Form; 3 4/** 5 * Class DropdownElement 6 * 7 * Represents a HTML select. Please note that this does not support multiple selected options! 8 * 9 * @package dokuwiki\Form 10 */ 11class DropdownElement extends InputElement { 12 13 protected $options = array(); 14 15 protected $value = ''; 16 17 /** 18 * @param string $name The name of this form element 19 * @param string $options The available options 20 * @param string $label The label text for this element (will be autoescaped) 21 */ 22 public function __construct($name, $options, $label = '') { 23 parent::__construct('dropdown', $name, $label); 24 $this->rmattr('type'); 25 $this->options($options); 26 } 27 28 /** 29 * Get or set the options of the Dropdown 30 * 31 * Options can be given as associative array (value => label) or as an 32 * indexd array (label = value) or as an array of arrays. In the latter 33 * case an element has to look as follows: 34 * option-value => array ( 35 * 'label' => option-label, 36 * 'attrs' => array ( 37 * attr-key => attr-value, ... 38 * ) 39 * ) 40 * 41 * @param null|array $options 42 * @return $this|array 43 */ 44 public function options($options = null) { 45 if($options === null) return $this->options; 46 if(!is_array($options)) throw new \InvalidArgumentException('Options have to be an array'); 47 $this->options = array(); 48 49 foreach($options as $key => $val) { 50 if(is_int($key)) { 51 $this->options[$val] = array('label' => (string) $val); 52 } elseif (!is_array($val)) { 53 $this->options[$key] = array('label' => (string) $val); 54 } else { 55 if (!key_exists('label', $val)) throw new \InvalidArgumentException('If option is given as array, it has to have a "label"-key!'); 56 $this->options[$key] = $val; 57 } 58 } 59 $this->val(''); // set default value (empty or first) 60 return $this; 61 } 62 63 /** 64 * Gets or sets an attribute 65 * 66 * When no $value is given, the current content of the attribute is returned. 67 * An empty string is returned for unset attributes. 68 * 69 * When a $value is given, the content is set to that value and the Element 70 * itself is returned for easy chaining 71 * 72 * @param string $name Name of the attribute to access 73 * @param null|string $value New value to set 74 * @return string|$this 75 */ 76 public function attr($name, $value = null) { 77 if(strtolower($name) == 'multiple') { 78 throw new \InvalidArgumentException('Sorry, the dropdown element does not support the "multiple" attribute'); 79 } 80 return parent::attr($name, $value); 81 } 82 83 /** 84 * Get or set the current value 85 * 86 * When setting a value that is not defined in the options, the value is ignored 87 * and the first option's value is selected instead 88 * 89 * @param null|string $value The value to set 90 * @return $this|string 91 */ 92 public function val($value = null) { 93 if($value === null) return $this->value; 94 95 if(isset($this->options[$value])) { 96 $this->value = $value; 97 } else { 98 // unknown value set, select first option instead 99 $keys = array_keys($this->options); 100 $this->value = (string) array_shift($keys); 101 } 102 103 return $this; 104 } 105 106 /** 107 * Create the HTML for the select it self 108 * 109 * @return string 110 */ 111 protected function mainElementHTML() { 112 if($this->useInput) $this->prefillInput(); 113 114 $html = '<select ' . buildAttributes($this->attrs()) . '>'; 115 foreach($this->options as $key => $val) { 116 $selected = ($key == $this->value) ? ' selected="selected"' : ''; 117 $attrs = ''; 118 if (is_array($val['attrs'])) { 119 array_walk($val['attrs'],function (&$aval, $akey){$aval = hsc($akey).'="'.hsc($aval).'"';}); 120 $attrs = join(' ', $val['attrs']); 121 } 122 $html .= '<option' . $selected . ' value="' . hsc($key) . '" '.$attrs.'>' . hsc($val['label']) . '</option>'; 123 } 124 $html .= '</select>'; 125 126 return $html; 127 } 128 129} 130