1<?php 2 3namespace dokuwiki\plugin\data\Form; 4 5use dokuwiki\Form\InputElement; 6use dokuwiki\Form\OptGroup; 7 8/** 9 * Overrides some methods in parent in order to add not yet supported 10 * multivalue capabilities. 11 */ 12class DropdownElement extends \dokuwiki\Form\DropdownElement 13{ 14 /** @var string[] the currently set values */ 15 protected $values = []; 16 17 /** @var \dokuwiki\plugin\data\Form\OptGroup[] */ 18 protected $optGroups = []; 19 20 21 /** 22 * Override the parent constructor because it instantiates an OptGroup 23 * which does not handle multivalues 24 * 25 * @param string $name 26 * @param array $options 27 * @param string $label 28 */ 29 public function __construct($name, $options, $label = '') 30 { 31 InputElement::__construct('dropdown', $name, $label); 32 $this->rmattr('type'); 33 $this->optGroups[''] = new \dokuwiki\plugin\data\Form\OptGroup(null, $options); 34 $this->val(''); 35 } 36 37 /** 38 * Adds multivalue capabilities 39 * 40 * @param array $value 41 * @return DropdownElement|string|array 42 */ 43 public function val($value = null) 44 { 45 // getter 46 if ($value === null) { 47 if (isset($this->attributes['multiple'])) { 48 return $this->values; 49 } else { 50 return $this->values[0]; 51 } 52 } 53 54 // setter 55 $this->values = $this->setValuesInOptGroups((array)$value); 56 if (!$this->values) { 57 // unknown value set, select first option instead 58 $this->values = $this->setValuesInOptGroups((array)$this->getFirstOptionKey()); 59 } 60 61 return $this; 62 } 63 64 /** 65 * Skips over parent's \InvalidArgumentException thrown for 'multiple' 66 * 67 * @param $name 68 * @param $value 69 * @return DropdownElement|string 70 */ 71 public function attr($name, $value = null) 72 { 73 return InputElement::attr($name, $value); 74 } 75 76 /** 77 * Returns the first option's key 78 * 79 * @return string 80 */ 81 protected function getFirstOptionKey() 82 { 83 $options = $this->options(); 84 if (!empty($options)) { 85 $keys = array_keys($options); 86 return (string)array_shift($keys); 87 } 88 foreach ($this->optGroups as $optGroup) { 89 $options = $optGroup->options(); 90 if (!empty($options)) { 91 $keys = array_keys($options); 92 return (string)array_shift($keys); 93 } 94 } 95 96 return ''; // should not happen 97 } 98 99 /** 100 * Set the value in the OptGroups, including the optgroup for the options without optgroup. 101 * 102 * @param string[] $values The values to be set 103 * @return string[] The values actually set 104 */ 105 protected function setValuesInOptGroups($values) 106 { 107 $valueset = []; 108 109 /** @var \dokuwiki\plugin\data\Form\OptGroup $optGroup */ 110 foreach ($this->optGroups as $optGroup) { 111 $found = $optGroup->storeValues($values); 112 $values = array_diff($values, $found); 113 $valueset = array_merge($valueset, $found); 114 } 115 116 return $valueset; 117 } 118 119 /** 120 * @inheritDoc 121 */ 122 protected function mainElementHTML() 123 { 124 $attr = $this->attrs(); 125 if (isset($attr['multiple'])) { 126 // use array notation when multiple values are allowed 127 $attr['name'] .= '[]'; 128 } elseif ($this->useInput) { 129 // prefilling is only supported for non-multi fields 130 $this->prefillInput(); 131 } 132 133 unset($attr['selected']); 134 135 $html = '<select ' . buildAttributes($attr) . '>'; 136 $html = array_reduce( 137 $this->optGroups, 138 function ($html, OptGroup $optGroup) { 139 return $html . $optGroup->toHTML(); 140 }, 141 $html 142 ); 143 $html .= '</select>'; 144 145 return $html; 146 } 147} 148