|
- <?php
-
- namespace dokuwiki\Form;
-
- /**
- * Class DropdownElement
- *
- * Represents a HTML select. Please not that prefilling with input data only works for single values.
- *
- * @package dokuwiki\Form
- */
- class DropdownElement extends InputElement
- {
- /** @var array OptGroup[] */
- protected $optGroups = [];
-
- /** @var string[] the currently set values */
- protected $values = [];
-
- /**
- * @param string $name The name of this form element
- * @param array $options The available options
- * @param string $label The label text for this element (will be autoescaped)
- */
- public function __construct($name, $options, $label = '')
- {
- parent::__construct('dropdown', $name, $label);
- $this->rmattr('type');
- $this->optGroups[''] = new OptGroup(null, $options);
- $this->val('');
- }
-
- /**
- * Add an `<optgroup>` and respective options
- *
- * @param string $label
- * @param array $options
- * @return OptGroup a reference to the added optgroup
- * @throws \InvalidArgumentException
- */
- public function addOptGroup($label, $options)
- {
- if (empty($label)) {
- throw new \InvalidArgumentException(hsc('<optgroup> must have a label!'));
- }
- $this->optGroups[$label] = new OptGroup($label, $options);
- return end($this->optGroups);
- }
-
- /**
- * Set or get the optgroups of an Dropdown-Element.
- *
- * optgroups have to be given as associative array
- * * the key being the label of the group
- * * the value being an array of options as defined in @param null|array $optGroups
- * @return OptGroup[]|DropdownElement
- * @see OptGroup::options()
- *
- */
- public function optGroups($optGroups = null)
- {
- if ($optGroups === null) {
- return $this->optGroups;
- }
- if (!is_array($optGroups)) {
- throw new \InvalidArgumentException(hsc('Argument must be an associative array of label => [options]!'));
- }
- $this->optGroups = [];
- foreach ($optGroups as $label => $options) {
- $this->addOptGroup($label, $options);
- }
- return $this;
- }
-
- /**
- * Get or set the options of the Dropdown
- *
- * Options can be given as associative array (value => label) or as an
- * indexd array (label = value) or as an array of arrays. In the latter
- * case an element has to look as follows:
- * option-value => array (
- * 'label' => option-label,
- * 'attrs' => array (
- * attr-key => attr-value, ...
- * )
- * )
- *
- * @param null|array $options
- * @return $this|array
- */
- public function options($options = null)
- {
- if ($options === null) {
- return $this->optGroups['']->options();
- }
- $this->optGroups[''] = new OptGroup(null, $options);
- return $this;
- }
-
- /**
- * Get or set the current value
- *
- * When setting a value that is not defined in the options, the value is ignored
- * and the first option's value is selected instead
- *
- * @param null|string|string[] $value The value to set
- * @return $this|string|string[]
- */
- public function val($value = null)
- {
- // getter
- if ($value === null) {
- if (isset($this->attributes['multiple'])) {
- return $this->values;
- } else {
- return $this->values[0];
- }
- }
-
- // setter
- $this->values = $this->setValuesInOptGroups((array) $value);
- if (!$this->values) {
- // unknown value set, select first option instead
- $this->values = $this->setValuesInOptGroups((array) $this->getFirstOptionKey());
- }
-
- return $this;
- }
-
- /**
- * Returns the first option's key
- *
- * @return string
- */
- protected function getFirstOptionKey()
- {
- $options = $this->options();
- if (!empty($options)) {
- $keys = array_keys($options);
- return (string)array_shift($keys);
- }
- foreach ($this->optGroups as $optGroup) {
- $options = $optGroup->options();
- if (!empty($options)) {
- $keys = array_keys($options);
- return (string)array_shift($keys);
- }
- }
-
- return ''; // should not happen
- }
-
- /**
- * Set the value in the OptGroups, including the optgroup for the options without optgroup.
- *
- * @param string[] $values The values to be set
- * @return string[] The values actually set
- */
- protected function setValuesInOptGroups($values)
- {
- $valueset = [];
-
- /** @var OptGroup $optGroup */
- foreach ($this->optGroups as $optGroup) {
- $found = $optGroup->storeValues($values);
- $values = array_diff($values, $found);
- $valueset = array_merge($valueset, $found);
- }
-
- return $valueset;
- }
-
- /**
- * Create the HTML for the select it self
- *
- * @return string
- */
- protected function mainElementHTML()
- {
- $attr = $this->attrs();
- if (isset($attr['multiple'])) {
- // use array notation when multiple values are allowed
- $attr['name'] .= '[]';
- } elseif ($this->useInput) {
- // prefilling is only supported for non-multi fields
- $this->prefillInput();
- }
-
- $html = '<select ' . buildAttributes($attr) . '>';
- $html = array_reduce(
- $this->optGroups,
- static fn($html, OptGroup $optGroup) => $html . $optGroup->toHTML(),
- $html
- );
- $html .= '</select>';
-
- return $html;
- }
- }
|