major update
This commit is contained in:
@@ -76,6 +76,212 @@ function multiSelectFilter(
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a standard select filter field.
|
||||
*
|
||||
* @param array<int, array{id:mixed,description:mixed,translate?:bool,attributes?:array<string,mixed>}> $items
|
||||
* @param array<string,mixed> $labelAttributes
|
||||
* @param array<string,mixed> $selectAttributes
|
||||
*/
|
||||
function selectFilter(
|
||||
string $id,
|
||||
string $label,
|
||||
array $items,
|
||||
string $selected = '',
|
||||
array $labelAttributes = [],
|
||||
array $selectAttributes = []
|
||||
): void {
|
||||
$labelClass = trim((string) ($labelAttributes['class'] ?? ''));
|
||||
if ($labelClass === '') {
|
||||
$labelClass = 'app-field';
|
||||
} elseif (!str_contains($labelClass, 'app-field')) {
|
||||
$labelClass = 'app-field ' . $labelClass;
|
||||
}
|
||||
$labelAttributes['class'] = $labelClass;
|
||||
|
||||
$selectAttributes['id'] = $id;
|
||||
|
||||
?>
|
||||
<label<?php uiRenderAttributes($labelAttributes); ?>>
|
||||
<span><?php e(t($label)); ?></span>
|
||||
<select<?php uiRenderAttributes($selectAttributes); ?>>
|
||||
<?php foreach ($items as $item): ?>
|
||||
<?php $itemId = (string) ($item['id'] ?? ''); ?>
|
||||
<?php $itemLabel = (string) ($item['description'] ?? ''); ?>
|
||||
<?php $translateLabel = !array_key_exists('translate', $item) || (bool) $item['translate']; ?>
|
||||
<?php $optionAttributes = is_array($item['attributes'] ?? null) ? $item['attributes'] : []; ?>
|
||||
<?php $optionAttributes['value'] = $itemId; ?>
|
||||
<?php if ($itemId === $selected): ?>
|
||||
<?php $optionAttributes['selected'] = true; ?>
|
||||
<?php endif; ?>
|
||||
<option<?php uiRenderAttributes($optionAttributes); ?>>
|
||||
<?php if ($translateLabel): ?>
|
||||
<?php e(t($itemLabel)); ?>
|
||||
<?php else: ?>
|
||||
<?php e($itemLabel); ?>
|
||||
<?php endif; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a full toolbar from a filter schema.
|
||||
*
|
||||
* @param array<int,array<string,mixed>> $schema
|
||||
* @param array<string,mixed> $active
|
||||
* @param array<string,array<int,array<string,mixed>>> $optionSets
|
||||
*/
|
||||
function renderGridFilterToolbar(array $schema, array $active = [], array $optionSets = []): void
|
||||
{
|
||||
foreach ($schema as $field) {
|
||||
if (!is_array($field)) {
|
||||
continue;
|
||||
}
|
||||
if (($field['render'] ?? true) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$key = trim((string) ($field['key'] ?? ''));
|
||||
if ($key === '') {
|
||||
continue;
|
||||
}
|
||||
$type = strtolower(trim((string) ($field['type'] ?? 'text')));
|
||||
if (!in_array($type, ['text', 'date', 'number', 'hidden', 'select', 'multi_csv'], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$inputId = trim((string) ($field['input_id'] ?? ''));
|
||||
if ($inputId === '') {
|
||||
$inputId = $key . '-filter';
|
||||
}
|
||||
|
||||
$label = (string) ($field['label'] ?? $key);
|
||||
$placeholder = (string) ($field['placeholder'] ?? '');
|
||||
$defaultValue = $field['default'] ?? '';
|
||||
$activeValue = $active[$key] ?? $defaultValue;
|
||||
$labelAttributes = is_array($field['label_attributes'] ?? null) ? $field['label_attributes'] : [];
|
||||
$inputAttributes = is_array($field['input_attributes'] ?? null) ? $field['input_attributes'] : [];
|
||||
|
||||
if ($type === 'hidden') {
|
||||
$inputAttributes['type'] = 'hidden';
|
||||
$inputAttributes['id'] = $inputId;
|
||||
$inputAttributes['value'] = is_scalar($activeValue) ? (string) $activeValue : '';
|
||||
echo '<input';
|
||||
uiRenderAttributes($inputAttributes);
|
||||
echo '>';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type === 'select') {
|
||||
$items = uiResolveFilterItems($field, $optionSets);
|
||||
$selected = is_scalar($activeValue) ? (string) $activeValue : (string) $defaultValue;
|
||||
selectFilter(
|
||||
$inputId,
|
||||
$label,
|
||||
$items,
|
||||
$selected,
|
||||
$labelAttributes,
|
||||
$inputAttributes
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type === 'multi_csv') {
|
||||
$items = uiResolveFilterItems($field, $optionSets);
|
||||
$selected = uiNormalizeFilterSelection($activeValue);
|
||||
multiSelectFilter(
|
||||
$inputId,
|
||||
$label,
|
||||
$placeholder !== '' ? $placeholder : 'Select options',
|
||||
$items,
|
||||
$selected
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$labelClass = trim((string) ($labelAttributes['class'] ?? ''));
|
||||
if ($labelClass === '') {
|
||||
$labelClass = 'app-field';
|
||||
} elseif (!str_contains($labelClass, 'app-field')) {
|
||||
$labelClass = 'app-field ' . $labelClass;
|
||||
}
|
||||
$labelAttributes['class'] = $labelClass;
|
||||
|
||||
$inputAttributes['id'] = $inputId;
|
||||
$inputAttributes['type'] = $type === 'number' ? 'number' : $type;
|
||||
if ($placeholder !== '' && !isset($inputAttributes['placeholder']) && $type === 'text') {
|
||||
$inputAttributes['placeholder'] = t($placeholder);
|
||||
}
|
||||
if (in_array($type, ['text', 'date', 'number'], true)) {
|
||||
$inputAttributes['value'] = is_scalar($activeValue) ? (string) $activeValue : '';
|
||||
}
|
||||
|
||||
echo '<label';
|
||||
uiRenderAttributes($labelAttributes);
|
||||
echo '>';
|
||||
echo '<span>';
|
||||
e(t($label));
|
||||
echo '</span>';
|
||||
echo '<input';
|
||||
uiRenderAttributes($inputAttributes);
|
||||
echo '>';
|
||||
echo '</label>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $field
|
||||
* @param array<string,array<int,array<string,mixed>>> $optionSets
|
||||
* @return array<int,array<string,mixed>>
|
||||
*/
|
||||
function uiResolveFilterItems(array $field, array $optionSets): array
|
||||
{
|
||||
$allowed = $field['allowed'] ?? null;
|
||||
if (is_array($allowed)) {
|
||||
return array_values(array_filter(array_map(static function (mixed $item): array {
|
||||
if (is_array($item)) {
|
||||
return $item;
|
||||
}
|
||||
if (is_scalar($item)) {
|
||||
$value = (string) $item;
|
||||
return ['id' => $value, 'description' => $value, 'translate' => false];
|
||||
}
|
||||
return [];
|
||||
}, $allowed), static fn (array $item): bool => $item !== []));
|
||||
}
|
||||
|
||||
$optionsKey = trim((string) ($field['options_key'] ?? ''));
|
||||
if ($optionsKey !== '' && isset($optionSets[$optionsKey])) {
|
||||
return array_values(array_filter($optionSets[$optionsKey], static fn (array $item): bool => $item !== []));
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
function uiNormalizeFilterSelection(mixed $value): array
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return array_values(array_filter(array_map(
|
||||
static fn (mixed $item): string => trim((string) $item),
|
||||
$value
|
||||
), static fn (string $item): bool => $item !== ''));
|
||||
}
|
||||
if (!is_scalar($value)) {
|
||||
return [];
|
||||
}
|
||||
$text = trim((string) $value);
|
||||
if ($text === '') {
|
||||
return [];
|
||||
}
|
||||
return array_values(array_filter(array_map('trim', explode(',', $text)), static fn (string $item): bool => $item !== ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a multi-select form field for data entry.
|
||||
*
|
||||
@@ -144,6 +350,31 @@ function multiSelectForm(
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render arbitrary HTML attributes from a key-value map.
|
||||
*
|
||||
* @param array<string,mixed> $attributes
|
||||
*/
|
||||
function uiRenderAttributes(array $attributes): void
|
||||
{
|
||||
foreach ($attributes as $name => $value) {
|
||||
$attrName = trim((string) $name);
|
||||
if ($attrName === '') {
|
||||
continue;
|
||||
}
|
||||
if ($value === false || $value === null) {
|
||||
continue;
|
||||
}
|
||||
if ($value === true) {
|
||||
echo ' ' . $attrName;
|
||||
continue;
|
||||
}
|
||||
echo ' ' . $attrName . '="';
|
||||
e((string) $value);
|
||||
echo '"';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve nav active state for one or many paths.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user