TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,515 @@
|
||||
<?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\Container;
|
||||
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use TYPO3\CMS\Backend\Form\Event\ModifyFileReferenceControlsEvent;
|
||||
use TYPO3\CMS\Backend\Form\Event\ModifyFileReferenceEnabledControlsEvent;
|
||||
use TYPO3\CMS\Backend\Form\InlineStackProcessor;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Imaging\IconFactory;
|
||||
use TYPO3\CMS\Core\Imaging\IconSize;
|
||||
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Resource\ProcessedFile;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Schema\Capability\TcaSchemaCapability;
|
||||
use TYPO3\CMS\Core\Type\Bitmask\Permission;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
|
||||
/**
|
||||
* Render a single file reference.
|
||||
*
|
||||
* This container is called by FilesControlContainer to render a single file (reference). The container is also
|
||||
* called by FormEngine for an incoming ajax request to expand an existing file (reference) or to create a new one.
|
||||
*
|
||||
* This container creates the outer HTML of single file (references) - e.g. drag and drop and delete buttons.
|
||||
* For rendering of the record itself processing is handed over to FullRecordContainer.
|
||||
*/
|
||||
class FileReferenceContainer extends AbstractContainer
|
||||
{
|
||||
private const string FILE_REFERENCE_TABLE = 'sys_file_reference';
|
||||
private const string FOREIGN_SELECTOR = 'uid_local';
|
||||
|
||||
/**
|
||||
* File reference data used for JSON output
|
||||
*/
|
||||
protected array $fileReferenceData = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly IconFactory $iconFactory,
|
||||
private readonly InlineStackProcessor $inlineStackProcessor,
|
||||
private readonly EventDispatcherInterface $eventDispatcher,
|
||||
private readonly ResourceFactory $resourceFactory,
|
||||
private readonly ConnectionPool $connectionPool,
|
||||
private readonly UriBuilder $uriBuilder,
|
||||
) {}
|
||||
|
||||
public function render(): array
|
||||
{
|
||||
// Send a mapping information to the browser via JSON:
|
||||
// e.g. data[<curTable>][<curId>][<curField>] => data-<pid>-<parentTable>-<parentId>-<parentField>-<curTable>-<curId>-<curField>
|
||||
$formPrefix = $this->inlineStackProcessor->getFormPrefixFromStructure($this->data['inlineStructure']);
|
||||
$domObjectId = $this->inlineStackProcessor->getDomObjectIdPrefixFromStructure($this->data['inlineStructure'], $this->data['inlineFirstPid']);
|
||||
|
||||
$this->fileReferenceData = $this->data['inlineData'];
|
||||
$this->fileReferenceData['map'][$formPrefix] = $domObjectId;
|
||||
|
||||
$resultArray = $this->initializeResultArray();
|
||||
$resultArray['inlineData'] = $this->fileReferenceData;
|
||||
|
||||
$html = '';
|
||||
$classes = [];
|
||||
$combinationHtml = '';
|
||||
$record = $this->data['databaseRow'];
|
||||
$uid = $record['uid'] ?? 0;
|
||||
$appendFormFieldNames = '[' . self::FILE_REFERENCE_TABLE . '][' . $uid . ']';
|
||||
$objectId = $domObjectId . '-' . self::FILE_REFERENCE_TABLE . '-' . $uid;
|
||||
$isNewRecord = $this->data['command'] === 'new';
|
||||
$hiddenFieldName = (string)($this->data['processedTca']['ctrl']['enablecolumns']['disabled'] ?? '');
|
||||
if (!$this->data['isInlineDefaultLanguageRecordInLocalizedParentContext']) {
|
||||
if ($isNewRecord || $this->data['isInlineChildExpanded']) {
|
||||
$fileReferenceData = $this->renderFileReference($this->data);
|
||||
$html = $fileReferenceData['html'];
|
||||
$resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fileReferenceData, false);
|
||||
} else {
|
||||
// This class is the marker for the JS-function to check if the full content has already been loaded
|
||||
$classes[] = 't3js-not-loaded';
|
||||
}
|
||||
if ($isNewRecord) {
|
||||
// Add pid of file reference as hidden field
|
||||
$html .= '<input type="hidden" name="data' . htmlspecialchars($appendFormFieldNames)
|
||||
. '[pid]" value="' . htmlspecialchars((string)$record['pid']) . '"/>';
|
||||
// Tell DataHandler this file reference is expanded
|
||||
$ucFieldName = 'uc[inlineView]'
|
||||
. '[' . $this->data['inlineTopMostParentTableName'] . ']'
|
||||
. '[' . $this->data['inlineTopMostParentUid'] . ']'
|
||||
. htmlspecialchars($appendFormFieldNames);
|
||||
$html .= '<input type="hidden" name="' . htmlspecialchars($ucFieldName)
|
||||
. '" value="' . (int)$this->data['isInlineChildExpanded'] . '" />';
|
||||
} else {
|
||||
// Set additional field for processing for saving
|
||||
$html .= '<input type="hidden" name="cmd' . htmlspecialchars($appendFormFieldNames)
|
||||
. '[delete]" value="1" disabled="disabled" />';
|
||||
if ($hiddenFieldName !== ''
|
||||
&& (!$this->data['isInlineChildExpanded']
|
||||
|| !in_array($hiddenFieldName, $this->data['columnsToProcess'], true))
|
||||
) {
|
||||
$isHidden = (bool)($record[$hiddenFieldName] ?? false);
|
||||
$html .= '<input type="checkbox" class="d-none" data-formengine-input-name="data'
|
||||
. htmlspecialchars($appendFormFieldNames)
|
||||
. '[' . htmlspecialchars($hiddenFieldName) . ']" value="1"'
|
||||
. ($isHidden ? ' checked="checked"' : '') . ' />';
|
||||
$html .= '<input type="input" class="d-none" name="data' . htmlspecialchars($appendFormFieldNames)
|
||||
. '[' . htmlspecialchars($hiddenFieldName) . ']" value="' . (int)$isHidden . '" />';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->data['inlineParentConfig']['renderFieldsOnly'] ?? false) {
|
||||
// Render "body" part only
|
||||
$resultArray['html'] = $html . $combinationHtml;
|
||||
return $resultArray;
|
||||
}
|
||||
|
||||
// Render header row and content (if expanded)
|
||||
if ($this->data['isInlineDefaultLanguageRecordInLocalizedParentContext']) {
|
||||
$classes[] = 'panel-placeholder';
|
||||
}
|
||||
if ($record[$hiddenFieldName] ?? false) {
|
||||
$classes[] = 'panel-hidden';
|
||||
}
|
||||
if ($isNewRecord) {
|
||||
$classes[] = 'inlineIsNewRecord';
|
||||
}
|
||||
|
||||
// The hashed object id needs a non-numeric prefix, the value is used as ID selector in JavaScript
|
||||
$hashedObjectId = 'hash-' . md5($objectId);
|
||||
$containerAttributes = [
|
||||
'id' => $objectId . '_div',
|
||||
'class' => 'form-irre-object panel panel-default ' . trim(implode(' ', $classes)),
|
||||
'data-object-uid' => $record['uid'] ?? 0,
|
||||
'data-object-id' => $objectId,
|
||||
'data-object-id-hash' => $hashedObjectId,
|
||||
'data-object-parent-group' => $domObjectId . '-' . self::FILE_REFERENCE_TABLE,
|
||||
'data-field-name' => $appendFormFieldNames,
|
||||
'data-topmost-parent-table' => $this->data['inlineTopMostParentTableName'],
|
||||
'data-topmost-parent-uid' => $this->data['inlineTopMostParentUid'],
|
||||
'data-placeholder-record' => $this->data['isInlineDefaultLanguageRecordInLocalizedParentContext'] ? '1' : '0',
|
||||
];
|
||||
|
||||
$isExpanded = $this->data['isInlineChildExpanded'] ?? false;
|
||||
$ariaControls = htmlspecialchars($objectId . '_fields', ENT_QUOTES | ENT_HTML5);
|
||||
$resultArray['html'] = '
|
||||
<div ' . GeneralUtility::implodeAttributes($containerAttributes, true) . '>
|
||||
<div class="panel-heading">
|
||||
<div class="panel-heading-row">
|
||||
' . $this->renderFileHeader($isExpanded, $ariaControls) . '
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-collapse collapse' . ($isExpanded ? ' show' : '') . '" id="' . $ariaControls . '">' . $html . $combinationHtml . '</div>
|
||||
</div>';
|
||||
|
||||
return $resultArray;
|
||||
}
|
||||
|
||||
protected function renderFileReference(array $data): array
|
||||
{
|
||||
$data['tabAndInlineStack'][] = [
|
||||
'inline',
|
||||
$this->inlineStackProcessor->getDomObjectIdPrefixFromStructure($this->data['inlineStructure'], $data['inlineFirstPid'])
|
||||
. '-'
|
||||
. $data['tableName']
|
||||
. '-'
|
||||
. $data['databaseRow']['uid'],
|
||||
];
|
||||
|
||||
return $this->nodeFactory->create(array_replace_recursive($data, [
|
||||
'inlineData' => $this->fileReferenceData,
|
||||
'renderType' => 'fullRecordContainer',
|
||||
]))->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the HTML header for the file, such as the title, toggle-function, drag'n'drop, etc.
|
||||
* Later on the command-icons are inserted here, too.
|
||||
*/
|
||||
protected function renderFileHeader(bool $isExpanded, string $ariaControls): string
|
||||
{
|
||||
$languageService = $this->getLanguageService();
|
||||
|
||||
$databaseRow = $this->data['databaseRow'];
|
||||
$recordTitle = $this->getRecordTitle();
|
||||
|
||||
if (empty($recordTitle)) {
|
||||
$recordTitle = '<em>[' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title')) . ']</em>';
|
||||
}
|
||||
|
||||
$objectId = htmlspecialchars($this->inlineStackProcessor->getDomObjectIdPrefixFromStructure($this->data['inlineStructure'], $this->data['inlineFirstPid'])
|
||||
. '-' . self::FILE_REFERENCE_TABLE
|
||||
. '-' . ($databaseRow['uid'] ?? 0));
|
||||
|
||||
$altText = BackendUtility::getRecordIconAltText($databaseRow, self::FILE_REFERENCE_TABLE, false);
|
||||
|
||||
// Renders the header image (thumbnail, icon, or missing file indicator)
|
||||
$headerImage = '';
|
||||
$headerBadge = '';
|
||||
$isMissing = false;
|
||||
if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails'] ?? false) {
|
||||
$fileUid = $databaseRow[self::FOREIGN_SELECTOR][0]['uid'] ?? null;
|
||||
if (!empty($fileUid)) {
|
||||
try {
|
||||
$fileObject = $this->resourceFactory->getFileObject($fileUid);
|
||||
if ($fileObject->isMissing()) {
|
||||
$isMissing = true;
|
||||
$recordTitle = htmlspecialchars($fileObject->getName());
|
||||
$headerImage = '
|
||||
<div class="panel-icon" id="' . $objectId . '_iconcontainer">
|
||||
' . $this->iconFactory->getIcon('default-not-found', IconSize::SMALL)->render() . '
|
||||
</div>';
|
||||
$headerBadge = '
|
||||
<div class="panel-badge">
|
||||
<span class="badge badge-danger">'
|
||||
. htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.file_missing')) . '
|
||||
</span>
|
||||
</div>';
|
||||
} elseif ($fileObject->isImage() || $fileObject->isMediaFile()) {
|
||||
$imageSetup = $this->data['inlineParentConfig']['appearance']['headerThumbnail'] ?? [];
|
||||
$cropVariantCollection = CropVariantCollection::create($databaseRow['crop'] ?? '');
|
||||
if (!$cropVariantCollection->getCropArea()->isEmpty()) {
|
||||
$imageSetup['crop'] = $cropVariantCollection->getCropArea()->makeAbsoluteBasedOnFile($fileObject);
|
||||
}
|
||||
$processedImage = $fileObject->process(
|
||||
ProcessedFile::CONTEXT_IMAGECROPSCALEMASK,
|
||||
array_merge(['maxWidth' => 60, 'maxHeight' => 45], $imageSetup)
|
||||
);
|
||||
// Only use a thumbnail if the processing process was successful by checking if image width is set
|
||||
if ($processedImage->getProperty('width')) {
|
||||
$imageUrl = $processedImage->getPublicUrl() ?? '';
|
||||
$headerImage = '
|
||||
<div class="panel-thumbnail" id="' . $objectId . '_thumbnailcontainer">
|
||||
<img src="' . htmlspecialchars($imageUrl) . '" '
|
||||
. 'width="' . $processedImage->getProperty('width') . '" '
|
||||
. 'height="' . $processedImage->getProperty('height') . '" '
|
||||
. 'alt="" '
|
||||
. 'title="' . htmlspecialchars($altText) . '" '
|
||||
. 'loading="lazy">
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$fileObject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($headerImage === '' && !$isMissing) {
|
||||
$headerImage = '
|
||||
<div class="panel-icon" id="' . $objectId . '_iconcontainer">
|
||||
' . $this->iconFactory
|
||||
->getIconForRecord(self::FILE_REFERENCE_TABLE, $databaseRow, IconSize::SMALL)
|
||||
->setTitle($altText)
|
||||
->render() . '
|
||||
</div>';
|
||||
}
|
||||
|
||||
return '
|
||||
<button class="panel-button' . ($isExpanded ? '' : ' collapsed') . '" type="button"
|
||||
data-bs-toggle="collapse" data-bs-target="#' . $ariaControls . '"
|
||||
aria-expanded="' . ($isExpanded ? 'true' : 'false') . '" aria-controls="' . $ariaControls . '">
|
||||
<span class="caret"></span>
|
||||
' . $headerImage . '
|
||||
<div class="panel-title"><span id="' . $objectId . '_label">' . $recordTitle . '</span></div>
|
||||
' . $headerBadge . '
|
||||
</button>
|
||||
<div class="panel-actions t3js-formengine-irre-control">
|
||||
' . $this->renderFileReferenceHeaderControl() . '
|
||||
</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the control-icons for a file reference (e.g. create new, sorting, delete, disable/enable).
|
||||
*/
|
||||
protected function renderFileReferenceHeaderControl(): string
|
||||
{
|
||||
$controls = [];
|
||||
$databaseRow = $this->data['databaseRow'];
|
||||
$databaseRow += [
|
||||
'uid' => 0,
|
||||
];
|
||||
$parentConfig = $this->data['inlineParentConfig'];
|
||||
$languageService = $this->getLanguageService();
|
||||
$backendUser = $this->getBackendUserAuthentication();
|
||||
$isNewItem = str_starts_with((string)$databaseRow['uid'], 'NEW');
|
||||
$fileReferenceTableTca = $this->data['tcaSchemata']->get(self::FILE_REFERENCE_TABLE);
|
||||
$calcPerms = new Permission(
|
||||
$backendUser->calcPerms(BackendUtility::readPageAccess(
|
||||
(int)($this->data['parentPageRow']['uid'] ?? 0),
|
||||
$backendUser->getPagePermsClause(Permission::PAGE_SHOW)
|
||||
))
|
||||
);
|
||||
$event = $this->eventDispatcher->dispatch(
|
||||
new ModifyFileReferenceEnabledControlsEvent($this->data, $databaseRow)
|
||||
);
|
||||
if ($this->data['isInlineDefaultLanguageRecordInLocalizedParentContext']) {
|
||||
$controls['localize'] = $this->iconFactory
|
||||
->getIcon('actions-edit-localize-status-low', IconSize::SMALL)
|
||||
->setTitle($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_misc.xlf:localize.isLocalizable'))
|
||||
->render();
|
||||
}
|
||||
if ($event->isControlEnabled('info')) {
|
||||
if ($isNewItem) {
|
||||
$controls['info'] = '
|
||||
<span class="btn btn-default disabled">
|
||||
' . $this->iconFactory->getIcon('empty-empty', IconSize::SMALL)->render() . '
|
||||
</span>';
|
||||
} else {
|
||||
$controls['info'] = '
|
||||
<button type="button" class="btn btn-default" data-action="infowindow" data-info-table="' . htmlspecialchars('_FILE') . '" data-info-uid="' . (int)$databaseRow['uid_local'][0]['uid'] . '" title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:showInfo')) . '">
|
||||
' . $this->iconFactory->getIcon('actions-document-info', IconSize::SMALL)->render() . '
|
||||
</button>';
|
||||
}
|
||||
}
|
||||
// If the table is NOT a read-only table, then show these links:
|
||||
if (!($parentConfig['readOnly'] ?? false)
|
||||
&& !($fileReferenceTableTca->getCapability(TcaSchemaCapability::AccessReadOnly)->getValue() ?? false)
|
||||
&& !($this->data['isInlineDefaultLanguageRecordInLocalizedParentContext'] ?? false)
|
||||
) {
|
||||
if ($event->isControlEnabled('sort')) {
|
||||
$icon = 'actions-move-up';
|
||||
$class = '';
|
||||
if ((int)$parentConfig['inline']['first'] === (int)$databaseRow['uid']) {
|
||||
$class = ' disabled';
|
||||
$icon = 'empty-empty';
|
||||
}
|
||||
$controls['sort.up'] = '
|
||||
<button type="button" class="btn btn-default' . $class . '" data-action="sort" data-direction="up" title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:moveUp')) . '">
|
||||
' . $this->iconFactory->getIcon($icon, IconSize::SMALL)->render() . '
|
||||
</button>';
|
||||
|
||||
$icon = 'actions-move-down';
|
||||
$class = '';
|
||||
if ((int)$parentConfig['inline']['last'] === (int)$databaseRow['uid']) {
|
||||
$class = ' disabled';
|
||||
$icon = 'empty-empty';
|
||||
}
|
||||
$controls['sort.down'] = '
|
||||
<button type="button" class="btn btn-default' . $class . '" data-action="sort" data-direction="down" title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:moveDown')) . '">
|
||||
' . $this->iconFactory->getIcon($icon, IconSize::SMALL)->render() . '
|
||||
</button>';
|
||||
}
|
||||
$sysFileMetadataTableTca = $this->data['tcaSchemata']->has('sys_file_metadata') ? $this->data['tcaSchemata']->get('sys_file_metadata') : null;
|
||||
if (!$isNewItem
|
||||
&& ($languageField = ($sysFileMetadataTableTca?->getRawConfiguration()['languageField'] ?? false))
|
||||
&& $backendUser->check('tables_modify', 'sys_file_metadata')
|
||||
&& $event->isControlEnabled('edit')
|
||||
) {
|
||||
$languageId = (int)(is_array($databaseRow[$languageField] ?? null)
|
||||
? ($databaseRow[$languageField][0] ?? 0)
|
||||
: ($databaseRow[$languageField] ?? 0));
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_file_metadata');
|
||||
$metadataRecord = $queryBuilder
|
||||
->select('uid')
|
||||
->from('sys_file_metadata')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'file',
|
||||
$queryBuilder->createNamedParameter((int)$databaseRow['uid_local'][0]['uid'], Connection::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
$languageField,
|
||||
$queryBuilder->createNamedParameter($languageId, Connection::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->setMaxResults(1)
|
||||
->executeQuery()
|
||||
->fetchAssociative();
|
||||
if (!empty($metadataRecord)) {
|
||||
$url = (string)$this->uriBuilder->buildUriFromRoute('record_edit', [
|
||||
'edit[sys_file_metadata][' . (int)$metadataRecord['uid'] . ']' => 'edit',
|
||||
'module' => (string)($this->data['request']->getQueryParams()['module'] ?? ''),
|
||||
'returnUrl' => $this->data['returnUrl'],
|
||||
]);
|
||||
$controls['edit'] = '
|
||||
<a class="btn btn-default" href="' . htmlspecialchars($url) . '" title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.editMetadata')) . '">
|
||||
' . $this->iconFactory->getIcon('actions-open', IconSize::SMALL)->render() . '
|
||||
</a>';
|
||||
}
|
||||
}
|
||||
if ($event->isControlEnabled('delete') && $calcPerms->editContentPermissionIsGranted()) {
|
||||
$recordInfo = $this->data['databaseRow']['uid_local'][0]['title'] ?? $this->data['recordTitle'] ?? '';
|
||||
if ($this->getBackendUserAuthentication()->shallDisplayDebugInformation()) {
|
||||
$recordInfo .= ' [' . $this->data['tableName'] . ':' . $this->data['vanillaUid'] . ']';
|
||||
}
|
||||
$controls['delete'] = '
|
||||
<button type="button" class="btn btn-default t3js-editform-delete-inline-record" data-record-info="' . htmlspecialchars(trim($recordInfo)) . '" title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:delete')) . '">
|
||||
' . $this->iconFactory->getIcon('actions-edit-delete', IconSize::SMALL)->render() . '
|
||||
</button>';
|
||||
}
|
||||
if (($hiddenField = ($fileReferenceTableTca->getCapability(TcaSchemaCapability::RestrictionDisabledField)->getFieldName())) !== ''
|
||||
&& ($fileReferenceTableTca->hasField($hiddenField))
|
||||
&& $event->isControlEnabled('hide')
|
||||
&& (
|
||||
!($fileReferenceTableTca->getField($hiddenField)->getConfiguration()['exclude'] ?? false)
|
||||
|| $backendUser->check('non_exclude_fields', self::FILE_REFERENCE_TABLE . ':' . $hiddenField)
|
||||
)
|
||||
) {
|
||||
if ($databaseRow[$hiddenField] ?? false) {
|
||||
$controls['hide'] = '
|
||||
<button type="button" class="btn btn-default t3js-toggle-visibility-button" data-hidden-field="' . htmlspecialchars($hiddenField) . '" title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:unHide')) . '">
|
||||
' . $this->iconFactory->getIcon('actions-edit-unhide', IconSize::SMALL)->render() . '
|
||||
</button>';
|
||||
} else {
|
||||
$controls['hide'] = '
|
||||
<button type="button" class="btn btn-default t3js-toggle-visibility-button" data-hidden-field="' . htmlspecialchars($hiddenField) . '" title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:hide')) . '">
|
||||
' . $this->iconFactory->getIcon('actions-edit-hide', IconSize::SMALL)->render() . '
|
||||
</button>';
|
||||
}
|
||||
}
|
||||
if (($parentConfig['appearance']['useSortable'] ?? false) && $event->isControlEnabled('dragdrop')) {
|
||||
$controls['dragdrop'] = '
|
||||
<span class="btn btn-default sortableHandle" data-id="' . (int)$databaseRow['uid'] . '" title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move')) . '">
|
||||
' . $this->iconFactory->getIcon('actions-move-move', IconSize::SMALL)->render() . '
|
||||
</span>';
|
||||
}
|
||||
} elseif (($this->data['isInlineDefaultLanguageRecordInLocalizedParentContext'] ?? false)
|
||||
&& MathUtility::canBeInterpretedAsInteger($this->data['inlineParentUid'])
|
||||
&& $event->isControlEnabled('localize')
|
||||
) {
|
||||
$controls['localize'] = '
|
||||
<button type="button" class="btn btn-default t3js-synchronizelocalize-button" data-type="' . htmlspecialchars((string)$databaseRow['uid']) . '" title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_misc.xlf:localize')) . '">
|
||||
' . $this->iconFactory->getIcon('actions-document-localize', IconSize::SMALL)->render() . '
|
||||
</button>';
|
||||
}
|
||||
if ($lockInfo = BackendUtility::isRecordLocked(self::FILE_REFERENCE_TABLE, $databaseRow['uid'])) {
|
||||
$controls['locked'] = '
|
||||
<button type="button" class="btn btn-default" title="' . htmlspecialchars($lockInfo['msg']) . '">
|
||||
' . $this->iconFactory->getIcon('status-user-backend', IconSize::SMALL, 'overlay-edit')->render() . '
|
||||
</button>';
|
||||
}
|
||||
|
||||
// Get modified controls. This means their markup was modified, new controls were added or controls got removed.
|
||||
$controls = $this->eventDispatcher->dispatch(
|
||||
new ModifyFileReferenceControlsEvent($controls, $this->data, $databaseRow)
|
||||
)->getControls();
|
||||
|
||||
$out = '';
|
||||
if (($controls['edit'] ?? false) || ($controls['hide'] ?? false) || ($controls['delete'] ?? false)) {
|
||||
$out .= '
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
' . ($controls['edit'] ?? '') . ($controls['hide'] ?? '') . ($controls['delete'] ?? '') . '
|
||||
</div>';
|
||||
unset($controls['edit'], $controls['hide'], $controls['delete']);
|
||||
}
|
||||
if (($controls['info'] ?? false) || ($controls['new'] ?? false) || ($controls['sort.up'] ?? false) || ($controls['sort.down'] ?? false) || ($controls['dragdrop'] ?? false)) {
|
||||
$out .= '
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
' . ($controls['info'] ?? '') . ($controls['new'] ?? '') . ($controls['sort.up'] ?? '') . ($controls['sort.down'] ?? '') . ($controls['dragdrop'] ?? '') . '
|
||||
</div>';
|
||||
unset($controls['info'], $controls['new'], $controls['sort.up'], $controls['sort.down'], $controls['dragdrop']);
|
||||
}
|
||||
if ($controls['localize'] ?? false) {
|
||||
$out .= '<div class="btn-group btn-group-sm" role="group">' . $controls['localize'] . '</div>';
|
||||
unset($controls['localize']);
|
||||
}
|
||||
if ($controls !== [] && ($remainingControls = trim(implode('', $controls))) !== '') {
|
||||
$out .= '<div class="btn-group btn-group-sm" role="group">' . $remainingControls . '</div>';
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
protected function getRecordTitle(): string
|
||||
{
|
||||
$databaseRow = $this->data['databaseRow'];
|
||||
$fileRecord = $databaseRow['uid_local'][0]['row'] ?? null;
|
||||
|
||||
if ($fileRecord === null) {
|
||||
return $this->data['recordTitle'] ?: (string)$databaseRow['uid'];
|
||||
}
|
||||
|
||||
$title = '<span>' . $this->getLabelFieldForRecord($databaseRow, $fileRecord, 'name') . '</span>';
|
||||
|
||||
// In debug mode, add the table name to the record title
|
||||
if ($this->getBackendUserAuthentication()->shallDisplayDebugInformation()) {
|
||||
$title .= ' <span class="panel-meta"><code>[' . self::FILE_REFERENCE_TABLE . ']</code></span>';
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
protected function getLabelFieldForRecord(array $databaseRow, array $fileRecord, string $field): string
|
||||
{
|
||||
$value = '';
|
||||
|
||||
if (isset($databaseRow[$field])) {
|
||||
$value = htmlspecialchars((string)$databaseRow[$field]);
|
||||
} elseif (isset($fileRecord[$field])) {
|
||||
$value = htmlspecialchars((string)$fileRecord[$field]);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user