Returns <optgroup> and <options> tags for select

@param array $values
@param array $selected
@param int   $level
@return array
772221
private static function getOptions(array $values, array $selected, int $level = 0): array
    {
        $options = [];
        foreach ($values as $k => $v) {
            if (\strpos((string)$k, 'OPTGROUP') !== false) {
                $label = \str_replace(['&amp;nbsp;', '&amp;'], [Tags::NBSP, '&'], \htmlspecialchars((string)$v['name']));
                $optAttributes = ['label' => $label];
                if ($level > 0) {
                    $optAttributes['style'] = 'padding-left: '.(10 * $level).'px';
                }
                $options[] = Tags::optgroup(self::getOptions($v['options'], $selected, $level + 1), $optAttributes);
            } else {
                $optAttributes = [
                    'value' => $k,
                    'class' => 'opt-'.\str_replace('/', '', $k),
                ];
                if ($level > 0) {
                    $optAttributes['style'] = 'padding-left: '.(10 * $level).'px';
                }
                if (\in_array($k, $selected)) {
                    $optAttributes['selected'] = 'selected';
                }
                $options[] = Tags::option(
                    \str_replace(['&amp;nbsp;', '&amp;'], [Tags::NBSP, '&'], \htmlspecialchars((string)$v)),
                    $optAttributes
                );
            }
        }
        return $options;
    }
591113
public function buildSelectFields($fields)
    {
        $selectFields = [];
        foreach ((array)$fields as $key => $value) {
            if (is_int($key)) {
                $selectFields[$value] = true;
            } else {
                $selectFields[$key] = is_scalar($value) ? (bool)$value : $value;
            }
        }
        return $selectFields;
    }
962352
private function selectList($skip=0, $owner = 0, $level = 0)
    {
        $items = Eresus_CMS::getLegacyKernel()->sections->
            children($owner, Eresus_CMS::getLegacyKernel()->user['access']);
        $result = array(array(), array());
        foreach ($items as $item)
        {
            if ($item['id'] != $skip)
            {
                $item['caption'] = trim($item['caption']);
                if (empty($item['caption']))
                {
                    $item['caption'] = ADM_NA;
                }
                $result[0][] = $item['id'];
                $result[1][] = str_repeat('&nbsp;', $level*2).$item['caption'];
                $children = $this->selectList($skip, $item['id'], $level+1);
                $result[0] = array_merge($result[0], $children[0]);
                $result[1] = array_merge($result[1], $children[1]);
            }
        }
        return $result;
    }
638929
public function options($options)
    {
        return $this->addChildren($options, function ($text, $value) {
            if (is_array($text)) {
                return $this->optgroup($value, $text);
            }

            return Option::create()
                ->value($value)
                ->text($text)
                ->selectedIf($value === $this->value);
        });
    }
287959
protected function optionGroup($list, $label, $selected, array $attributes = [], array $optionsAttributes = [], $level = 0)
    {
        $html = [];
        $space = str_repeat("&nbsp;", $level);
        foreach ($list as $value => $display) {
            $optionAttributes = $optionsAttributes[$value] ?? [];
            if (is_iterable($display)) {
                $html[] = $this->optionGroup($display, $value, $selected, $attributes, $optionAttributes, $level+5);
            } else {
                $html[] = $this->option($space.$display, $value, $selected, $optionAttributes);
            }
        }
        return $this->toHtmlString('<optgroup label="' . e($space.$label, false) . '"' . $this->html->attributes($attributes) . '>' . implode('', $html) . '</optgroup>');
    }
1362162
protected function _checkNoSelected(array $options, array $selected, $isMultiply = false)
    {
        if ($isMultiply === 'multiple') {
            return array($options, $selected);
        }

        $_selected = array_pop($selected);

        if (!Arr::key($_selected, $options) && !empty($selected)) {
            $options = array_merge(array($_selected => $this->_translate('--No selected--')), $options);
        }

        return array($options, array($_selected));
    }
1328418
protected function addNewValues(array $selections, array $values)
    {
        if ($this->isAllowAdd()) {
            foreach ($values as $value) {
                if (!\in_array($value, $selections) && !\in_array((string) $value, $selections)) {
                    $selections[] = (string) $value;
                }
            }
        }

        return $selections;
    }
1140351
private static function getSelectOptions($list, $selectedValue) {
        $result = '';

        if ($selectedValue !== null && !is_array($selectedValue)) {
            $selectedValue = array($selectedValue);
        }

        foreach ($list as $item) {
            $itemAttr = array();
            $text = '';

            if ($item instanceof SelectListItem) {
                $text = $item->text;
                $itemAttr['value'] = $item->value;

                if ($item->disabled === true) {
                    $itemAttr['disabled'] = 'disabled';
                }

                if ($selectedValue === null && $item->selected === true) {
                    $itemAttr['selected'] = 'selected';
                }
                elseif ($selectedValue !== null && in_array($item->value, $selectedValue) === true) {
                    $itemAttr['selected'] = 'selected';
                }
            }
            else {
                $text = $item;

                if ($selectedValue !== null && in_array($item, $selectedValue)) {
                    $itemAttr['selected'] = 'selected';
                }
            }

            $attr = self::buildAttributes($itemAttr);

            $result .= '<option' . (!empty($attr) ? ' ' : '') . $attr . '>';
            $result .= htmlspecialchars($text);
            $result .= '</option>';
        }

        return $result;
    }
559326
public function getFormattedChoices(array $choices, $position, $selected)
    {
        $lines = [];

        foreach ($choices as $index => $choice) {
            $state = in_array($choice, $selected)
                ? self::CHOICE_SELECTED
                : self::CHOICE_NORMAL;

            $cursor = $index === $position
                ? self::CHOICE_HOVERED
                : self::CHOICE_NORMAL;

            // select which style to use
            $line = $this->style[$state][$cursor];

            // add the fancy fish eye symbol to make things prettier
            $choice = '  ' . unicode_to_string('\u25C9') . '  ' . $choice;

            $lines[] = sprintf($line, $this->fitText($this->window->getWidth(), $choice));
        }

        return $lines;
    }
1333109
public function selectArray($fields = null, $where = null, $orderBy = null, $limit = null): array
    {
        return self::select2($fields, $where, $orderBy, $limit);
    }
124714
public static function groupResult(array $original, array $keys, $level = 0)
    {
        $converted = [];
        $key = $keys[$level];
        $isDeepest = sizeof($keys) - 1 == $level;

        $level++;

        $filtered = [];
        foreach ($original as $k => $subArray) {

            $subArray = (array) $subArray;
            if (!isset($subArray[$key])) {
                throw new AssociationException(
                    "Index '" . $key . "' not found on level '" . $level . "'!"
                );
            }

            $thisLevel = $subArray[$key];

            if (is_object($thisLevel)) {
                $thisLevel = (string) $thisLevel;
            }

            if ($isDeepest) {
                $converted[$thisLevel] = $subArray;
            } else {
                $converted[$thisLevel] = [];
            }
            $filtered[$thisLevel][] = $subArray;
        }

        if (!$isDeepest) {
            foreach (array_keys($converted) as $value) {
                $converted[$value] = self::groupResult(
                    $filtered[$value],
                    $keys,
                    $level
                );
            }
        }

        return $converted;
    }
267231
function select($fields,$filter=NULL,array $options=NULL,$ttl=0) {
		list($sql,$args)=$this->stringify($fields,$filter,$options);
		$result=$this->db->exec($sql,$args,$ttl);
		$out=[];
		foreach ($result as &$row) {
			foreach ($row as $field=>&$val) {
				if (array_key_exists($field,$this->fields)) {
					if (!is_null($val) || !$this->fields[$field]['nullable'])
						$val=$this->db->value(
							$this->fields[$field]['pdo_type'],$val);
				}
				unset($val);
			}
			$out[]=$this->factory($row);
			unset($row);
		}
		return $out;
	}
902759
public static function convertTreeToOptionsMulti($data, $level = 0, $options = [], & $result) {
		if (empty($options['name_field'])) $options['name_field'] = 'name';
		if (!isset($options['i18n'])) $options['i18n'] = true;
		// skip_keys - convert to array
		if (!empty($options['skip_keys']) && !is_array($options['skip_keys'])) {
			$options['skip_keys'] = [$options['skip_keys']];
		}
		$inactive = i18n(null, \Object\Content\Messages::INFO_INACTIVE);
		// translate name column
		foreach ($data as $k => $v) {
			if (is_array($options['name_field'])) {
				$temp = [];
				foreach ($options['name_field'] as $k2 => $v2) {
					if (!isset($v[$v2])) continue;
					$temp[] = !empty($options['i18n']) ? i18n(null, $v[$v2]) : $v[$v2];
				}
				$data[$k]['name'] = implode(\Format::$symbol_comma . ' ', $temp);
			} else {
				$data[$k]['name'] = !empty($options['i18n']) ? i18n(null, $v[$options['name_field']]) : $v[$options['name_field']];
			}
			// handle inactive
			if (!empty($v['inactive']) && strpos($data[$k]['name'], \Format::$symbol_comma . ' ' . $inactive) !== false) {
				$data[$k]['name'].= \Format::$symbol_comma . ' ' . $inactive;
			}
		}
		// sorting
		if (!empty($options['i18n']) && $options['i18n'] !== 'skip_sorting') {
			array_key_sort($data, ['name' => SORT_ASC], ['name' => SORT_NATURAL]);
		}
		// assemble
		foreach ($data as $k => $v) {
			// if we are skipping certain keys
			if (!empty($options['skip_keys']) && in_array($k, $options['skip_keys'])) {
				continue;
			}
			// assemble variable
			$value = $v;
			$value['level'] = $level;
			if (!empty($options['icon_field'])) {
				$value['icon_class'] = \HTML::icon(['type' => $v[$options['icon_field']], 'class_only' => true]);
			}
			if (!empty($options['disabled_field'])) {
				$value['disabled'] = !empty($v[$options['disabled_field']]);
			}
			$result[$k] = $value;
			// if we have options
			if (!empty($v['options'])) {
				self::convertTreeToOptionsMulti($v['options'], $level + 1, $options, $result);
			}
		}
	}
503227
public function renderAPMOptionsDrop(array $options, string $selected = null): string
    {
        $droplist = null;
        $labels = array_keys($this->offices);
        foreach ($options as $key => $value) {
            $droplist .= in_array($key, $labels) ? $value : null;
            $droplist .= $this->renderAPMOptionsSelected($key, $value, $selected);
            $droplist .= ($key === 'AP&M 7456') ? '</optgroup>' : null;
        }

        return $droplist;
    }
138029
public function setSelected(bool $selected) : Option
    {
        if ($selected) {
            $this->tag->setAttribute('selected', 'selected');
        } else {
            $this->tag->removeAttribute('selected');
        }

        return $this;
    }
1009943
function getSelectValues (select, selectedOptions) {
    var value = [],
        options = selectedOptions || select.selectedOptions,
        opt;

    for (var i = 0, len = options.length; i < len; i++) {
      opt = options[i];

      if (!(opt.disabled || opt.parentNode.tagName === 'OPTGROUP' && opt.parentNode.disabled)) {
        value.push(opt.value || opt.text);
      }
    }

    if (!select.multiple) {
      return !value.length ? null : value[0];
    }

    return value;
  }
547886
protected function renderOptions(array $options, $selection)
	{
		$html = '';

		foreach($options as $key => $val) {
			if(is_array($val) === false) {
				$selected = ($key == $selection) ? ' selected' : null;
				$html .= '<option value="' . $key . '"' . $selected . '>' . $val . '</option>';
			} else {
				$html .= '<optgroup label="' . $key . '">' . $this->renderOptions($val, $selection) . '</optgroup>';
			}
		}

		return $html;
	}