18638ead5SAndreas Gohr<?php 28638ead5SAndreas Gohrnamespace dokuwiki\Form; 38638ead5SAndreas Gohr 48638ead5SAndreas Gohr/** 58638ead5SAndreas Gohr * Class DropdownElement 68638ead5SAndreas Gohr * 78638ead5SAndreas Gohr * Represents a HTML select. Please note that this does not support multiple selected options! 88638ead5SAndreas Gohr * 98638ead5SAndreas Gohr * @package dokuwiki\Form 108638ead5SAndreas Gohr */ 118638ead5SAndreas Gohrclass DropdownElement extends InputElement { 128638ead5SAndreas Gohr 13*238a072bSMichael Grosse /** @var OptGroup */ 14*238a072bSMichael Grosse protected $options = null; 15*238a072bSMichael Grosse 16*238a072bSMichael Grosse /** @var array OptGroup[] */ 17*238a072bSMichael Grosse protected $optGroups = array(); 188638ead5SAndreas Gohr 198638ead5SAndreas Gohr protected $value = ''; 208638ead5SAndreas Gohr 218638ead5SAndreas Gohr /** 228638ead5SAndreas Gohr * @param string $name The name of this form element 238638ead5SAndreas Gohr * @param string $options The available options 248638ead5SAndreas Gohr * @param string $label The label text for this element (will be autoescaped) 258638ead5SAndreas Gohr */ 268638ead5SAndreas Gohr public function __construct($name, $options, $label = '') { 278638ead5SAndreas Gohr parent::__construct('dropdown', $name, $label); 28693978b1SMichael Grosse $this->rmattr('type'); 29*238a072bSMichael Grosse $this->options = new OptGroup(null, $options); 30*238a072bSMichael Grosse $this->val(''); 31*238a072bSMichael Grosse } 32*238a072bSMichael Grosse 33*238a072bSMichael Grosse /** 34*238a072bSMichael Grosse * @param $label 35*238a072bSMichael Grosse * @param $options 36*238a072bSMichael Grosse * @return mixed 37*238a072bSMichael Grosse * @throws \Exception 38*238a072bSMichael Grosse */ 39*238a072bSMichael Grosse public function addOptGroup($label, $options) { 40*238a072bSMichael Grosse if (empty($label)) { 41*238a072bSMichael Grosse throw new \InvalidArgumentException(hsc('<optgroup> must have a label!')); 42*238a072bSMichael Grosse } 43*238a072bSMichael Grosse $this->optGroups[] = new OptGroup($label, $options); 44*238a072bSMichael Grosse return end($this->optGroups); 45*238a072bSMichael Grosse } 46*238a072bSMichael Grosse 47*238a072bSMichael Grosse /** 48*238a072bSMichael Grosse * Set or get the optgroups of an Dropdown-Element. 49*238a072bSMichael Grosse * 50*238a072bSMichael Grosse * optgroups have to be given as associative array 51*238a072bSMichael Grosse * * the key being the label of the group 52*238a072bSMichael Grosse * * the value being an array of options as defined in @see OptGroup::options() 53*238a072bSMichael Grosse * 54*238a072bSMichael Grosse * @param null|array $optGroups 55*238a072bSMichael Grosse * @return array 56*238a072bSMichael Grosse */ 57*238a072bSMichael Grosse public function optGroups($optGroups = null) { 58*238a072bSMichael Grosse if($optGroups === null) { 59*238a072bSMichael Grosse return $this->optGroups; 60*238a072bSMichael Grosse } 61*238a072bSMichael Grosse if (!is_array($optGroups)) { 62*238a072bSMichael Grosse throw new \InvalidArgumentException(hsc('Argument must be an associative array of label => [options]!')); 63*238a072bSMichael Grosse } 64*238a072bSMichael Grosse $this->optGroups = array(); 65*238a072bSMichael Grosse foreach ($optGroups as $label => $options) { 66*238a072bSMichael Grosse $this->addOptGroup($label, $options); 67*238a072bSMichael Grosse } 688638ead5SAndreas Gohr } 698638ead5SAndreas Gohr 708638ead5SAndreas Gohr /** 718638ead5SAndreas Gohr * Get or set the options of the Dropdown 728638ead5SAndreas Gohr * 738638ead5SAndreas Gohr * Options can be given as associative array (value => label) or as an 74795955b2SMichael Grosse * indexd array (label = value) or as an array of arrays. In the latter 75795955b2SMichael Grosse * case an element has to look as follows: 76795955b2SMichael Grosse * option-value => array ( 77795955b2SMichael Grosse * 'label' => option-label, 78795955b2SMichael Grosse * 'attrs' => array ( 79795955b2SMichael Grosse * attr-key => attr-value, ... 80795955b2SMichael Grosse * ) 81795955b2SMichael Grosse * ) 828638ead5SAndreas Gohr * 838638ead5SAndreas Gohr * @param null|array $options 848638ead5SAndreas Gohr * @return $this|array 858638ead5SAndreas Gohr */ 868638ead5SAndreas Gohr public function options($options = null) { 87*238a072bSMichael Grosse if ($options === null) { 88*238a072bSMichael Grosse return $this->options->options(); 898638ead5SAndreas Gohr } 90*238a072bSMichael Grosse $this->options = new OptGroup(null, $options); 918638ead5SAndreas Gohr return $this; 928638ead5SAndreas Gohr } 938638ead5SAndreas Gohr 948638ead5SAndreas Gohr /** 958638ead5SAndreas Gohr * Gets or sets an attribute 968638ead5SAndreas Gohr * 978638ead5SAndreas Gohr * When no $value is given, the current content of the attribute is returned. 988638ead5SAndreas Gohr * An empty string is returned for unset attributes. 998638ead5SAndreas Gohr * 1008638ead5SAndreas Gohr * When a $value is given, the content is set to that value and the Element 1018638ead5SAndreas Gohr * itself is returned for easy chaining 1028638ead5SAndreas Gohr * 1038638ead5SAndreas Gohr * @param string $name Name of the attribute to access 1048638ead5SAndreas Gohr * @param null|string $value New value to set 1058638ead5SAndreas Gohr * @return string|$this 1068638ead5SAndreas Gohr */ 1078638ead5SAndreas Gohr public function attr($name, $value = null) { 1088638ead5SAndreas Gohr if(strtolower($name) == 'multiple') { 1098638ead5SAndreas Gohr throw new \InvalidArgumentException('Sorry, the dropdown element does not support the "multiple" attribute'); 1108638ead5SAndreas Gohr } 1118638ead5SAndreas Gohr return parent::attr($name, $value); 1128638ead5SAndreas Gohr } 1138638ead5SAndreas Gohr 1148638ead5SAndreas Gohr /** 1158638ead5SAndreas Gohr * Get or set the current value 1168638ead5SAndreas Gohr * 1178638ead5SAndreas Gohr * When setting a value that is not defined in the options, the value is ignored 1188638ead5SAndreas Gohr * and the first option's value is selected instead 1198638ead5SAndreas Gohr * 1208638ead5SAndreas Gohr * @param null|string $value The value to set 1218638ead5SAndreas Gohr * @return $this|string 1228638ead5SAndreas Gohr */ 1238638ead5SAndreas Gohr public function val($value = null) { 1248638ead5SAndreas Gohr if($value === null) return $this->value; 1258638ead5SAndreas Gohr 126*238a072bSMichael Grosse $value_exists = $this->setValueInOptGroups($value); 127*238a072bSMichael Grosse 128*238a072bSMichael Grosse if($value_exists) { 1298638ead5SAndreas Gohr $this->value = $value; 1308638ead5SAndreas Gohr } else { 1318638ead5SAndreas Gohr // unknown value set, select first option instead 132*238a072bSMichael Grosse $this->value = $this->getFirstOption(); 133*238a072bSMichael Grosse $this->setValueInOptGroups($this->value); 1348638ead5SAndreas Gohr } 1358638ead5SAndreas Gohr 1368638ead5SAndreas Gohr return $this; 1378638ead5SAndreas Gohr } 1388638ead5SAndreas Gohr 1398638ead5SAndreas Gohr /** 140*238a072bSMichael Grosse * Returns the first options as it will be rendered in HTML 141*238a072bSMichael Grosse * 142*238a072bSMichael Grosse * @return string 143*238a072bSMichael Grosse */ 144*238a072bSMichael Grosse protected function getFirstOption() { 145*238a072bSMichael Grosse $options = $this->options(); 146*238a072bSMichael Grosse if (!empty($options)) { 147*238a072bSMichael Grosse return (string) array_shift(array_keys($options)); 148*238a072bSMichael Grosse } 149*238a072bSMichael Grosse foreach ($this->optGroups as $optGroup) { 150*238a072bSMichael Grosse $options = $optGroup->options(); 151*238a072bSMichael Grosse if (!empty($options)) { 152*238a072bSMichael Grosse return (string) array_shift(array_keys($options)); 153*238a072bSMichael Grosse } 154*238a072bSMichael Grosse } 155*238a072bSMichael Grosse } 156*238a072bSMichael Grosse 157*238a072bSMichael Grosse /** 158*238a072bSMichael Grosse * Set the value in the OptGroups, including the optgroup for the options without optgroup. 159*238a072bSMichael Grosse * 160*238a072bSMichael Grosse * @param string $value 161*238a072bSMichael Grosse * @return bool 162*238a072bSMichael Grosse */ 163*238a072bSMichael Grosse protected function setValueInOptGroups($value) { 164*238a072bSMichael Grosse $value_exists = $this->options->setValue($value); 165*238a072bSMichael Grosse foreach ($this->optGroups as $optGroup) { 166*238a072bSMichael Grosse $value_exists = $optGroup->setValue($value) || $value_exists; 167*238a072bSMichael Grosse } 168*238a072bSMichael Grosse return $value_exists; 169*238a072bSMichael Grosse } 170*238a072bSMichael Grosse 171*238a072bSMichael Grosse /** 1728638ead5SAndreas Gohr * Create the HTML for the select it self 1738638ead5SAndreas Gohr * 1748638ead5SAndreas Gohr * @return string 1758638ead5SAndreas Gohr */ 1768638ead5SAndreas Gohr protected function mainElementHTML() { 1778638ead5SAndreas Gohr if($this->useInput) $this->prefillInput(); 1788638ead5SAndreas Gohr 1798638ead5SAndreas Gohr $html = '<select ' . buildAttributes($this->attrs()) . '>'; 180*238a072bSMichael Grosse $html .= $this->options->toHTML(); 181*238a072bSMichael Grosse $html = array_reduce($this->optGroups, function($html, OptGroup $optGroup) {return $html . $optGroup->toHTML();}, $html); 1828638ead5SAndreas Gohr $html .= '</select>'; 1838638ead5SAndreas Gohr 1848638ead5SAndreas Gohr return $html; 1858638ead5SAndreas Gohr } 1868638ead5SAndreas Gohr 1878638ead5SAndreas Gohr} 188