259 lines
13 KiB
PHP
259 lines
13 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* This file is part of the TYPO3 CMS project.
|
|
*
|
|
* It is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, either version 2
|
|
* of the License, or any later version.
|
|
*
|
|
* For the full copyright and license information, please read the
|
|
* LICENSE.txt file that was distributed with this source code.
|
|
*
|
|
* The TYPO3 project - inspiring people to share!
|
|
*/
|
|
|
|
namespace TYPO3\CMS\Backend\Form\Element;
|
|
|
|
use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
|
|
use TYPO3\CMS\Core\Imaging\IconFactory;
|
|
use TYPO3\CMS\Core\Imaging\IconSize;
|
|
use TYPO3\CMS\Core\Page\JavaScriptModuleInstruction;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
use TYPO3\CMS\Core\Utility\StringUtility;
|
|
|
|
/**
|
|
* Renders table permission options for each available table.
|
|
*
|
|
* @internal Only used in be_groups for the "combined read & write" table permission list.
|
|
*/
|
|
final class TablePermissionElement extends AbstractFormElement
|
|
{
|
|
private const array Permissions = [
|
|
'none' => 'none',
|
|
'select' => 'select',
|
|
'modify' => 'modify',
|
|
];
|
|
|
|
public function __construct(
|
|
private readonly IconFactory $iconFactory,
|
|
) {}
|
|
|
|
public function render(): array
|
|
{
|
|
$resultArray = $this->initializeResultArray();
|
|
|
|
$parameterArray = $this->data['parameterArray'];
|
|
$config = $parameterArray['fieldConf']['config'];
|
|
$elementFieldName = $parameterArray['itemFormElName'];
|
|
$currentValue = ['modify' => [], 'select' => []];
|
|
if (is_array($parameterArray['itemFormElValue']['modify'] ?? false)
|
|
&& is_array($parameterArray['itemFormElValue']['select'] ?? false)
|
|
) {
|
|
$currentValue = $parameterArray['itemFormElValue'];
|
|
}
|
|
$readOnly = (bool)($config['readOnly'] ?? false);
|
|
|
|
$availableTables = $config['items'] ?? [];
|
|
if (empty($availableTables)) {
|
|
// Early return in case the field does not contain any items
|
|
return $resultArray;
|
|
}
|
|
|
|
$tablesConfiguration = [];
|
|
$lang = $this->getLanguageService();
|
|
$itemArrayModify = array_flip($currentValue['modify']);
|
|
$itemArraySelect = array_flip($currentValue['select']);
|
|
$elementId = StringUtility::getUniqueId('formengine-table-permission-');
|
|
|
|
foreach ($availableTables as $table) {
|
|
$permissions = [];
|
|
foreach (self::Permissions as $permission) {
|
|
$permissions[$permission] = [
|
|
'label' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:be_groups.tables_modify.permissions.' . $permission),
|
|
'attributes' => [
|
|
'type' => 'radio',
|
|
'class' => 'form-check-input t3js-table-permissions-item t3js-multi-record-selection-check',
|
|
'value' => $permission,
|
|
'name' => $elementId . '[' . $table['value'] . ']',
|
|
'id' => $elementId . '[' . $table['value'] . '][' . $permission . ']',
|
|
'data-table' => $table['value'],
|
|
],
|
|
];
|
|
}
|
|
|
|
if (isset($itemArrayModify[$table['value']])) {
|
|
$permissions[self::Permissions['modify']]['attributes']['checked'] = 'checked';
|
|
} elseif (isset($itemArraySelect[$table['value']])) {
|
|
$permissions[self::Permissions['select']]['attributes']['checked'] = 'checked';
|
|
} else {
|
|
$permissions[self::Permissions['none']]['attributes']['checked'] = 'checked';
|
|
}
|
|
|
|
if ($readOnly) {
|
|
foreach (self::Permissions as $permission) {
|
|
$permissions[$permission]['attributes']['disabled'] = 'disabled';
|
|
}
|
|
}
|
|
|
|
$tablesConfiguration[] = [
|
|
'permissions' => $permissions,
|
|
'label' => [
|
|
'id' => $elementId . '-' . $table['value'] . '-label',
|
|
'icon' => $this->getIconForTable(!empty($table['icon']) ? $table['icon'] : 'empty-empty'),
|
|
'title' => $lang->sL($table['label']),
|
|
'value' => $table['value'],
|
|
],
|
|
];
|
|
}
|
|
|
|
$modifyStateFieldName = htmlspecialchars($elementFieldName);
|
|
$selectStateFieldName = htmlspecialchars(str_replace($this->data['fieldName'], $config['selectFieldName'], $elementFieldName));
|
|
|
|
$fieldInformationResult = $this->renderFieldInformation();
|
|
$fieldInformationHtml = $fieldInformationResult['html'];
|
|
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
|
|
|
|
$html[] = '<typo3-formengine-element-tablepermission modifyStateFieldName="' . $modifyStateFieldName . '" selectStateFieldName="' . $selectStateFieldName . '">';
|
|
$html[] = '<div class="formengine-field-item t3js-formengine-field-item" data-formengine-validation-rules="' . htmlspecialchars($this->getValidationDataAsJsonString($config)) . '">';
|
|
$html[] = $fieldInformationHtml;
|
|
|
|
if (!$readOnly) {
|
|
$html[] = '<input type="hidden" name="' . $modifyStateFieldName . '" value="' . implode(',', $currentValue['modify']) . '">';
|
|
$html[] = '<input type="hidden" name="' . $selectStateFieldName . '" value="' . implode(',', $currentValue['select']) . '">';
|
|
}
|
|
|
|
$tableRows = [];
|
|
foreach ($tablesConfiguration as $tableConfiguration) {
|
|
$tableRows[] = '<tr role="radiogroup" aria-labelledby="' . $tableConfiguration['label']['id'] . '">';
|
|
foreach ($tableConfiguration['permissions'] as $key => $permission) {
|
|
$tableRows[] = '<td class="col-radiogroup">';
|
|
$tableRows[] = '<div class="form-check form-check-inline" data-multi-record-selection-identifier="' . $elementId . '-' . $key . '" data-multi-record-selection-element="true">';
|
|
$tableRows[] = '<input ' . GeneralUtility::implodeAttributes($permission['attributes'], true, true) . '>';
|
|
$tableRows[] = '<label class="form-check-label" for="' . $permission['attributes']['id'] . '">' . htmlspecialchars($permission['label']) . '</label>';
|
|
$tableRows[] = '</div>';
|
|
$tableRows[] = '</td>';
|
|
}
|
|
$tableRows[] = '<td class="col-title col-border-left">';
|
|
$tableRows[] = '<label class="label-block nowrap-disabled" id="' . $tableConfiguration['label']['id'] . '">';
|
|
$tableRows[] = '<span>' . $tableConfiguration['label']['icon'] . '</span>';
|
|
$tableRows[] = htmlspecialchars($this->appendValueToLabelInDebugMode($tableConfiguration['label']['title'], $tableConfiguration['label']['value']));
|
|
$tableRows[] = '</label>';
|
|
$tableRows[] = '</td>';
|
|
$tableRows[] = '</tr>';
|
|
}
|
|
|
|
$html[] = '<div id="' . $elementId . '">';
|
|
$html[] = '<div class="table-fit">';
|
|
$html[] = '<table class="table table-hover">';
|
|
$html[] = '<thead>';
|
|
$html[] = '<tr>';
|
|
foreach (self::Permissions as $permission) {
|
|
$html[] = '<th data-multi-record-selection-identifier="' . $elementId . '-' . $permission . '">';
|
|
$html[] = $this->getRecordSelectionCheckActions($permission === self::Permissions['none'] ? ['all'] : ['all', 'none', 'toggle'], $readOnly);
|
|
$html[] = '</th>';
|
|
}
|
|
$html[] = '<th class="col-title col-border-left">' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.th.name')) . '</th>';
|
|
$html[] = '</tr>';
|
|
$html[] = '</thead>';
|
|
|
|
$html[] = '<tbody>' . implode(LF, $tableRows) . '</tbody>';
|
|
$html[] = '</table>';
|
|
$html[] = '</div>';
|
|
$html[] = '</div>';
|
|
$html[] = '</div>';
|
|
|
|
if (!$readOnly) {
|
|
$resultArray['javaScriptModules'][] = JavaScriptModuleInstruction::create('@typo3/backend/form-engine/element/table-permission-element.js');
|
|
$resultArray['javaScriptModules'][] = JavaScriptModuleInstruction::create('@typo3/backend/multi-record-selection.js');
|
|
}
|
|
|
|
$html[] = '</typo3-formengine-element-tablepermission>';
|
|
|
|
$resultArray['html'] = $this->wrapWithFieldsetAndLegend(implode(LF, $html));
|
|
return $resultArray;
|
|
}
|
|
|
|
protected function wrapWithFieldsetAndLegend(string $innerHTML): string
|
|
{
|
|
$legend = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:be_groups.tables_modify'));
|
|
if ($this->getBackendUser()->shallDisplayDebugInformation()) {
|
|
$legend .= ' <code>[' . ($this->data['parameterArray']['fieldConf']['config']['selectFieldName'] ?? '') . ', ' . $this->data['fieldName'] . ']</code>';
|
|
}
|
|
$html = [];
|
|
$html[] = '<fieldset>';
|
|
$html[] = '<legend class="form-label t3js-formengine-label">' . $legend . '</legend>';
|
|
$html[] = $innerHTML;
|
|
$html[] = '</fieldset>';
|
|
return implode(LF, $html);
|
|
}
|
|
|
|
private function getIconForTable(string $icon): string
|
|
{
|
|
return FormEngineUtility::getIconHtml($icon);
|
|
}
|
|
|
|
private function getRecordSelectionCheckActions(array $optionsToShow, bool $readOnly): string
|
|
{
|
|
$checkboxOptions = [
|
|
'all' => '
|
|
<li>
|
|
<button type="button" class="dropdown-item" disabled data-multi-record-selection-check-action="check-all" title="' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.checkAll') . '">
|
|
<span class="dropdown-item-columns">
|
|
<span class="dropdown-item-column dropdown-item-column-icon" aria-hidden="true">
|
|
' . $this->iconFactory->getIcon('actions-selection-elements-all', IconSize::SMALL)->render() . '
|
|
</span>
|
|
<span class="dropdown-item-column dropdown-item-column-title">
|
|
' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.checkAll') . '
|
|
</span>
|
|
</span>
|
|
</button>
|
|
</li>',
|
|
'none' => '
|
|
<li>
|
|
<button type="button" class="dropdown-item" disabled data-multi-record-selection-check-action="check-none" title="' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.uncheckAll') . '">
|
|
<span class="dropdown-item-columns">
|
|
<span class="dropdown-item-column dropdown-item-column-icon" aria-hidden="true">
|
|
' . $this->iconFactory->getIcon('actions-selection-elements-none', IconSize::SMALL)->render() . '
|
|
</span>
|
|
<span class="dropdown-item-column dropdown-item-column-title">
|
|
' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.uncheckAll') . '
|
|
</span>
|
|
</span>
|
|
</button>
|
|
</li>',
|
|
'toggle' => '
|
|
<li>
|
|
<button type="button" class="dropdown-item" data-multi-record-selection-check-action="toggle" title="' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleSelection') . '">
|
|
<span class="dropdown-item-columns">
|
|
<span class="dropdown-item-column dropdown-item-column-icon" aria-hidden="true">
|
|
' . $this->iconFactory->getIcon('actions-selection-elements-invert', IconSize::SMALL)->render() . '
|
|
</span>
|
|
<span class="dropdown-item-column dropdown-item-column-title">
|
|
' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleSelection') . '
|
|
</span>
|
|
</span>
|
|
</button>
|
|
</li>',
|
|
];
|
|
|
|
$checkboxOptions = array_filter($checkboxOptions, static fn($checkboxOption) => in_array($checkboxOption, $optionsToShow, true), ARRAY_FILTER_USE_KEY);
|
|
if ($checkboxOptions === []) {
|
|
return '';
|
|
}
|
|
|
|
return '
|
|
<div class="dropdown">
|
|
<button type="button" class="dropdown-toggle dropdown-toggle-link t3js-multi-record-selection-check-actions-toggle" data-bs-toggle="dropdown" data-bs-boundary="window" aria-expanded="false" ' . ($readOnly ? ' disabled="disabled"' : '') . '>
|
|
<core:icon identifier="actions-selection" size="small" />
|
|
' . $this->iconFactory->getIcon('actions-selection', IconSize::SMALL)->render() . '
|
|
</button>
|
|
<ul class="dropdown-menu t3js-multi-record-selection-check-actions">
|
|
' . implode(LF, $checkboxOptions) . '
|
|
</ul>
|
|
</div>';
|
|
}
|
|
}
|