diff --git a/src/Contao/Dca/Builder/Legacy/LegacyDcaDataDefinitionBuilder.php b/src/Contao/Dca/Builder/Legacy/LegacyDcaDataDefinitionBuilder.php index 36707e751..efef53234 100644 --- a/src/Contao/Dca/Builder/Legacy/LegacyDcaDataDefinitionBuilder.php +++ b/src/Contao/Dca/Builder/Legacy/LegacyDcaDataDefinitionBuilder.php @@ -120,7 +120,6 @@ use function explode; use function in_array; use function is_array; -use function is_callable; use function next; use function parse_str; use function reset; diff --git a/src/Contao/Picker/PagePickerProvider.php b/src/Contao/Picker/PagePickerProvider.php index 35a7563ef..fce998447 100644 --- a/src/Contao/Picker/PagePickerProvider.php +++ b/src/Contao/Picker/PagePickerProvider.php @@ -67,7 +67,7 @@ public function __construct( */ public function getName() { - return 'ccaPagePicker'; + return 'pagePicker'; } /** diff --git a/src/Contao/View/Contao2BackendView/ActionHandler/AbstractListShowAllHandler.php b/src/Contao/View/Contao2BackendView/ActionHandler/AbstractListShowAllHandler.php index 008da09d2..fba145d39 100644 --- a/src/Contao/View/Contao2BackendView/ActionHandler/AbstractListShowAllHandler.php +++ b/src/Contao/View/Contao2BackendView/ActionHandler/AbstractListShowAllHandler.php @@ -76,6 +76,9 @@ use function array_key_exists; use function implode; +use function in_array; +use function is_string; +use function sprintf; use function str_contains; use function str_replace; use function trigger_error; @@ -154,7 +157,7 @@ public function __construct( } if (null === $tokenName) { $tokenName = System::getContainer()->getParameter('contao.csrf_token_name'); - assert(\is_string($tokenName)); + assert(is_string($tokenName)); // @codingStandardsIgnoreStart @trigger_error( @@ -264,7 +267,7 @@ protected function process(Action $action, EnvironmentInterface $environment) * * @return string */ - private function languageSwitcher(EnvironmentInterface $environment) + private function languageSwitcher(EnvironmentInterface $environment): string { $template = new ContaoBackendViewTemplate('dcbe_general_language_selector'); @@ -335,9 +338,9 @@ protected function translate($key, $domain, array $parameters = []) $translated = $this->translator->trans( - \sprintf('%s.%s', $domain, $key), + sprintf('%s.%s', $domain, $key), $parameters, - \sprintf('contao_%s', $domain) + sprintf('contao_%s', $domain) ); } @@ -494,7 +497,7 @@ protected function loadCollection(EnvironmentInterface $environment) * * @return string */ - private function generateHeaderButtons(EnvironmentInterface $environment) + private function generateHeaderButtons(EnvironmentInterface $environment): string { return (new GlobalButtonRenderer($environment))->render(); } @@ -512,7 +515,7 @@ private function renderCollection( EnvironmentInterface $environment, CollectionInterface $collection, array $grouping - ) { + ): void { $definition = $environment->getDataDefinition(); assert($definition instanceof ContainerInterface); @@ -578,7 +581,7 @@ private function addGroupHeader( &$groupClass, &$eoCount, &$remoteCur = null - ) { + ): void { if ($grouping && GroupAndSortingInformationInterface::GROUP_NONE !== $grouping['mode']) { $remoteNew = $this->renderGroupHeader( $grouping['property'], @@ -612,7 +615,7 @@ private function addGroupHeader( * * @return string When no information of panels can be obtained from the data container. */ - private function panel(EnvironmentInterface $environment, $ignoredPanels = []) + private function panel(EnvironmentInterface $environment, array $ignoredPanels = []): string { $view = $environment->getView(); assert($view instanceof BackendViewInterface); @@ -627,7 +630,7 @@ private function panel(EnvironmentInterface $environment, $ignoredPanels = []) * * @return array */ - private function getTableHead(EnvironmentInterface $environment) + private function getTableHead(EnvironmentInterface $environment): array { $definition = $environment->getDataDefinition(); assert($definition instanceof ContainerInterface); @@ -638,7 +641,7 @@ private function getTableHead(EnvironmentInterface $environment) $columns = $this->getSortingColumns($sorting); foreach ($formatter->getPropertyNames() as $field) { $tableHead[] = [ - 'class' => 'tl_folder_tlist col_' . $field . (\in_array($field, $columns) ? ' ordered_by' : ''), + 'class' => 'tl_folder_tlist col_' . $field . (in_array($field, $columns) ? ' ordered_by' : ''), 'content' => $this->translateButtonLabel($field, $definition->getName()) ]; } @@ -666,12 +669,12 @@ private function getTableHead(EnvironmentInterface $environment) * @SuppressWarnings(PHPMD.CamelCaseVariableName) */ private function renderGroupHeader( - $field, + string $field, ModelInterface $model, - $groupMode, - $groupLength, + string $groupMode, + int $groupLength, EnvironmentInterface $environment - ) { + ): ?string { $definition = $environment->getDataDefinition(); assert($definition instanceof ContainerInterface); @@ -716,7 +719,7 @@ protected function getSelectButtons(EnvironmentInterface $environment) * * @return bool */ - private function isSortable(EnvironmentInterface $environment) + private function isSortable(EnvironmentInterface $environment): bool { $definition = $environment->getDataDefinition(); assert($definition instanceof ContainerInterface); @@ -751,7 +754,7 @@ protected function renderPasteTopButton(EnvironmentInterface $environment, $sort assert($basicDefinition instanceof BasicDefinitionInterface); $dataProvider = $basicDefinition->getDataProvider(); - assert(\is_string($dataProvider)); + assert(is_string($dataProvider)); $filter->andModelIsFromProvider($dataProvider); @@ -784,7 +787,7 @@ protected function renderPasteTopButton(EnvironmentInterface $environment, $sort ContaoEvents::IMAGE_GET_HTML ); - return \sprintf( + return sprintf( '%s', $urlEvent->getUrl(), $this->translateButtonLabel('pastenew', $definition->getName()), @@ -802,7 +805,7 @@ protected function renderPasteTopButton(EnvironmentInterface $environment, $sort * @SuppressWarnings(PHPMD.Superglobals) * @SuppressWarnings(PHPMD.CamelCaseVariableName) */ - private function breadcrumb(EnvironmentInterface $environment) + private function breadcrumb(EnvironmentInterface $environment): ?string { $event = new GetBreadcrumbEvent($environment); @@ -830,7 +833,7 @@ private function breadcrumb(EnvironmentInterface $environment) * * @return array */ - private function getSortingColumns($sortingDefinition) + private function getSortingColumns(?GroupAndSortingDefinitionInterface $sortingDefinition): array { if (null === $sortingDefinition) { return []; @@ -855,7 +858,7 @@ private function getSortingColumns($sortingDefinition) * * @return array */ - private function getSelectContainer(EnvironmentInterface $environment) + private function getSelectContainer(EnvironmentInterface $environment): array { $inputProvider = $environment->getInputProvider(); assert($inputProvider instanceof InputProviderInterface); @@ -892,7 +895,7 @@ private function getSelectContainer(EnvironmentInterface $environment) * * @return void */ - private function handleEditAllButton(CollectionInterface $collection, EnvironmentInterface $environment) + private function handleEditAllButton(CollectionInterface $collection, EnvironmentInterface $environment): void { if (0 < $collection->count()) { return; diff --git a/src/Contao/View/Contao2BackendView/ActionHandler/CopyHandler.php b/src/Contao/View/Contao2BackendView/ActionHandler/CopyHandler.php index 754ef9d81..4b8669542 100644 --- a/src/Contao/View/Contao2BackendView/ActionHandler/CopyHandler.php +++ b/src/Contao/View/Contao2BackendView/ActionHandler/CopyHandler.php @@ -3,7 +3,7 @@ /** * This file is part of contao-community-alliance/dc-general. * - * (c) 2013-2023 Contao Community Alliance. + * (c) 2013-2024 Contao Community Alliance. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,14 +17,13 @@ * @author Sven Baumann * @author Richard Henkenjohann * @author Ingolf Steinhardt - * @copyright 2013-2023 Contao Community Alliance. + * @copyright 2013-2024 Contao Community Alliance. * @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ namespace ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\ActionHandler; -use Contao\System; use ContaoCommunityAlliance\Contao\Bindings\ContaoEvents; use ContaoCommunityAlliance\Contao\Bindings\Events\Controller\RedirectEvent; use ContaoCommunityAlliance\Contao\Bindings\Events\System\LogEvent; @@ -48,6 +47,8 @@ use ContaoCommunityAlliance\UrlBuilder\Contao\CsrfUrlBuilderFactory; use ContaoCommunityAlliance\UrlBuilder\UrlBuilder; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** * Class CopyModelController handles copy action on a model. @@ -65,19 +66,41 @@ class CopyHandler * * @var CsrfUrlBuilderFactory */ - private $securityUrlBuilder; + private CsrfUrlBuilderFactory $securityUrlBuilder; + + /** + * The request stack. + * + * @var RequestStack + */ + private RequestStack $requestStack; + + /** + * The URL generator. + * + * @var UrlGeneratorInterface + */ + private UrlGeneratorInterface $urlGenerator; /** * PasteHandler constructor. * * @param RequestScopeDeterminator $scopeDeterminator The request mode determinator. * @param CsrfUrlBuilderFactory $securityUrlBuilder The URL builder factory for URLs with security token. + * @param RequestStack $requestStack The request stack. + * @param UrlGeneratorInterface $urlGenerator The URL generator. */ - public function __construct(RequestScopeDeterminator $scopeDeterminator, CsrfUrlBuilderFactory $securityUrlBuilder) - { + public function __construct( + RequestScopeDeterminator $scopeDeterminator, + CsrfUrlBuilderFactory $securityUrlBuilder, + RequestStack $requestStack, + UrlGeneratorInterface $urlGenerator, + ) { $this->setScopeDeterminator($scopeDeterminator); $this->securityUrlBuilder = $securityUrlBuilder; + $this->requestStack = $requestStack; + $this->urlGenerator = $urlGenerator; } /** @@ -230,24 +253,38 @@ protected function redirect($environment, $copiedModelId) return; } - // Build a clean url to remove the copy related arguments instead of using the AddToUrlEvent. - $urlBuilder = new UrlBuilder(); - $urlBuilder - ->setPath('contao') - ->setQueryParameter('do', $inputProvider->getParameter('do')) - ->setQueryParameter('table', $copiedModelId->getDataProviderName()) - ->setQueryParameter('act', 'edit') - ->setQueryParameter('id', $copiedModelId->getSerialized()); - if (null !== ($pid = $inputProvider->getParameter('pid'))) { - $urlBuilder->setQueryParameter('pid', $pid); - } - - $redirectEvent = new RedirectEvent($this->securityUrlBuilder->create($urlBuilder->getUrl())->getUrl()); - if (null === ($dispatcher = $environment->getEventDispatcher())) { return; } + $request = $this->requestStack->getCurrentRequest(); + $routeName = $request?->attributes->get('_route'); + // Build a clean url to remove the copy related arguments instead of using the AddToUrlEvent. + $urlBuilder = new UrlBuilder(); + if ($routeName !== 'contao.backend') { + $params = [ + 'table' => $copiedModelId->getDataProviderName(), + 'act' => 'edit', + 'id' => $copiedModelId->getSerialized(), + ]; + if (null !== ($pid = $inputProvider->getParameter('pid'))) { + $params['pid'] = $pid; + } + $url = $this->urlGenerator->generate($routeName, $params); + } else { + $urlBuilder + ->setPath('contao') + ->setQueryParameter('do', $inputProvider->getParameter('do')) + ->setQueryParameter('table', $copiedModelId->getDataProviderName()) + ->setQueryParameter('act', 'edit') + ->setQueryParameter('id', $copiedModelId->getSerialized()); + if (null !== ($pid = $inputProvider->getParameter('pid'))) { + $urlBuilder->setQueryParameter('pid', $pid); + } + $url = $urlBuilder->getUrl(); + } + $redirectEvent = new RedirectEvent($this->securityUrlBuilder->create($url)->getUrl()); + $dispatcher->dispatch($redirectEvent, ContaoEvents::CONTROLLER_REDIRECT); } @@ -308,7 +345,7 @@ protected function process(EnvironmentInterface $environment) * * @return string|bool */ - private function checkPermission(EnvironmentInterface $environment) + private function checkPermission(EnvironmentInterface $environment): bool|string { if (null === ($definition = $environment->getDataDefinition())) { return false; diff --git a/src/Contao/View/Contao2BackendView/ActionHandler/MultipleHandler/SelectPropertyAllHandler.php b/src/Contao/View/Contao2BackendView/ActionHandler/MultipleHandler/SelectPropertyAllHandler.php index 38c8a5e40..f55073eb5 100644 --- a/src/Contao/View/Contao2BackendView/ActionHandler/MultipleHandler/SelectPropertyAllHandler.php +++ b/src/Contao/View/Contao2BackendView/ActionHandler/MultipleHandler/SelectPropertyAllHandler.php @@ -194,11 +194,11 @@ private function getCollection( $model->setID($property->getName()); $model->setProperty( 'name', - $property->getLabel() ?: $property->getName() + $this->translator->trans($property->getLabel(), [], $definition->getName()) ); $model->setProperty( 'description', - $property->getDescription() ?: $property->getName() + $this->translator->trans($property->getDescription(), [], $definition->getName()) ); $this->handlePropertyFileTree($property); diff --git a/src/Contao/View/Contao2BackendView/ActionHandler/SelectHandler.php b/src/Contao/View/Contao2BackendView/ActionHandler/SelectHandler.php index a4359aa33..58338f517 100644 --- a/src/Contao/View/Contao2BackendView/ActionHandler/SelectHandler.php +++ b/src/Contao/View/Contao2BackendView/ActionHandler/SelectHandler.php @@ -3,7 +3,7 @@ /** * This file is part of contao-community-alliance/dc-general. * - * (c) 2013-2023 Contao Community Alliance. + * (c) 2013-2024 Contao Community Alliance. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,7 +16,7 @@ * @author Stefan Heimes * @author Sven Baumann * @author Ingolf Steinhardt - * @copyright 2013-2023 Contao Community Alliance. + * @copyright 2013-2024 Contao Community Alliance. * @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -617,6 +617,9 @@ private function getSelectCollection(EnvironmentInterface $environment) foreach (($session['models'] ?? []) as $modelId) { $modelIds[] = ModelId::fromSerialized($modelId)->getId(); } + if ([] === $modelIds) { + return $dataProvider->getEmptyCollection(); + } $idProperty = method_exists($dataProvider, 'getIdProperty') ? $dataProvider->getIdProperty() : 'id'; $collection = $dataProvider->fetchAll( diff --git a/src/Contao/View/Contao2BackendView/ButtonRenderer.php b/src/Contao/View/Contao2BackendView/ButtonRenderer.php index 0a853704a..79084b3cc 100644 --- a/src/Contao/View/Contao2BackendView/ButtonRenderer.php +++ b/src/Contao/View/Contao2BackendView/ButtonRenderer.php @@ -325,10 +325,12 @@ private function hasPasteNewButton() private function buildCommand($command, $model, $previous, $next, $isCircularReference, $childIds) { $extra = (array) $command->getExtra(); - $attributes = ''; - - if (!empty($extra['attributes'])) { - $attributes .= sprintf($extra['attributes'], $model->getID()); + if ('' !== ($attributes = $extra['attributes'] ?? '')) { + // BC compatibility with legacy strings containing 'Edit item %s' + if (!str_contains($attributes, '%id%')) { + $attributes = sprintf($attributes, $model->getID()); + } + $attributes = strtr($attributes, ['%id%' => $model->getId()]); } $icon = $extra['icon']; diff --git a/src/Contao/View/Contao2BackendView/Controller/ClipboardController.php b/src/Contao/View/Contao2BackendView/Controller/ClipboardController.php index b393ee960..13060bb0d 100644 --- a/src/Contao/View/Contao2BackendView/Controller/ClipboardController.php +++ b/src/Contao/View/Contao2BackendView/Controller/ClipboardController.php @@ -3,7 +3,7 @@ /** * This file is part of contao-community-alliance/dc-general. * - * (c) 2013-2023 Contao Community Alliance. + * (c) 2013-2024 Contao Community Alliance. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,7 +17,7 @@ * @author Stefan Heimes * @author Sven Baumann * @author Ingolf Steinhardt - * @copyright 2013-2023 Contao Community Alliance. + * @copyright 2013-2024 Contao Community Alliance. * @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -46,9 +46,16 @@ use ContaoCommunityAlliance\DcGeneral\Event\ViewEvent; use ContaoCommunityAlliance\DcGeneral\InputProviderInterface; use ContaoCommunityAlliance\Translator\TranslatorInterface; +use ContaoCommunityAlliance\UrlBuilder\UrlBuilder; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use function array_shift; +use function in_array; +use function is_string; +use function parse_str; +use function sprintf; + /** * Class ClipboardController. * @@ -61,7 +68,7 @@ class ClipboardController implements EventSubscriberInterface * * @var RequestScopeDeterminator */ - private $scopeDeterminator; + private RequestScopeDeterminator $scopeDeterminator; /** * ClipboardController constructor. @@ -143,7 +150,7 @@ private function checkPermission(ActionEvent $event) if ( (('create' === $actionName) && (true === $basicDefinition->isCreatable())) || (('cut' === $actionName) && (true === $basicDefinition->isEditable())) - || (false === \in_array($actionName, ['create', 'cut'])) + || (false === in_array($actionName, ['create', 'cut'])) ) { return true; } @@ -162,7 +169,7 @@ private function checkPermission(ActionEvent $event) } $event->setResponse( - \sprintf( + sprintf( '
%s.
', $permissionMessage ) @@ -206,7 +213,15 @@ private function clearClipboard(ActionEvent $event, $redirect = true) $addToUrlEvent = new AddToUrlEvent('clipboard-item=&original-act=&act=' . $input->getParameter('original-act')); $eventDispatcher->dispatch($addToUrlEvent, ContaoEvents::BACKEND_ADD_TO_URL); - $redirectEvent = new RedirectEvent($addToUrlEvent->getUrl()); + $url = new UrlBuilder($addToUrlEvent->getUrl()); + parse_str($url->getQueryString(), $parameters); + foreach ($parameters as $name => $value) { + if ('' === $value) { + $url->unsetQueryParameter($name); + } + } + + $redirectEvent = new RedirectEvent($url->getUrl()); $eventDispatcher->dispatch($redirectEvent, ContaoEvents::CONTROLLER_REDIRECT); } @@ -272,11 +287,11 @@ private function addToClipboard(ActionEvent $event) assert($definition instanceof ContainerInterface); $providerName = $definition->getBasicDefinition()->getDataProvider(); - assert(\is_string($providerName)); + assert(is_string($providerName)); - $item = new UnsavedItem($clipboardActionName, $parentId, $providerName); + $item = new UnsavedItem($clipboardActionName, $parentId, $providerName); - // Remove other create items, there can only be one create item in the clipboard or many others + // Remove other create items, there can only be one create item in the clipboard or many others. $clipboard->clear(); } else { $modelIdRaw = $input->getParameter('source'); @@ -358,7 +373,7 @@ public function handleView(ViewEvent $event) $basicDefinition = $definition->getBasicDefinition(); $dataProvider = $basicDefinition->getDataProvider(); - assert(\is_string($dataProvider)); + assert(is_string($dataProvider)); $filter = new Filter(); $filter->andModelIsFromProvider($dataProvider); @@ -390,7 +405,7 @@ public function handleView(ViewEvent $event) $formatModelLabel = new FormatModelLabelEvent($environment, $model); $eventDispatcher->dispatch($formatModelLabel, DcGeneralEvents::FORMAT_MODEL_LABEL); $label = $formatModelLabel->getLabel(); - $label = \array_shift($label); + $label = array_shift($label); $label = $label['content']; } else { $model = $dataProvider->getEmptyModel(); @@ -398,7 +413,7 @@ public function handleView(ViewEvent $event) $translator = $environment->getTranslator(); assert($translator instanceof TranslatorInterface); - $label = $translator->translate('new.0', $item->getDataProviderName()); + $label = $translator->translate('new.label', $item->getDataProviderName()); } $options[$item->getClipboardId()] = ['item' => $item, 'model' => $model, 'label' => $label]; diff --git a/src/Contao/View/Contao2BackendView/EventListener/ColorPickerWizardListener.php b/src/Contao/View/Contao2BackendView/EventListener/ColorPickerWizardListener.php index b67b598da..0d7d68329 100644 --- a/src/Contao/View/Contao2BackendView/EventListener/ColorPickerWizardListener.php +++ b/src/Contao/View/Contao2BackendView/EventListener/ColorPickerWizardListener.php @@ -95,7 +95,7 @@ public static function getWizard($propInfo, EnvironmentInterface $environment) assert($translator instanceof TranslatorInterface); if (\array_key_exists('colorpicker', $propExtra) && $propExtra['colorpicker']) { - $pickerText = $translator->translate('colorpicker', 'dc-general'); + $pickerText = $translator->translate('colorPicker', 'dc-general'); $event = new GenerateHtmlEvent( 'pickcolor.svg', $pickerText, diff --git a/src/Contao/View/Contao2BackendView/FileSelect.php b/src/Contao/View/Contao2BackendView/FileSelect.php index b3bd27c9d..76b2a928e 100644 --- a/src/Contao/View/Contao2BackendView/FileSelect.php +++ b/src/Contao/View/Contao2BackendView/FileSelect.php @@ -362,7 +362,7 @@ private function setupItemContainer(ModelIdInterface $modelId) } /** - * Run the ajax request if is determine for run. + * Run the ajax request if it is determining for run. * * @SuppressWarnings(PHPMD.Superglobals) * diff --git a/src/Contao/View/Contao2BackendView/GlobalButtonRenderer.php b/src/Contao/View/Contao2BackendView/GlobalButtonRenderer.php index a45ed0cf6..d911ffa63 100644 --- a/src/Contao/View/Contao2BackendView/GlobalButtonRenderer.php +++ b/src/Contao/View/Contao2BackendView/GlobalButtonRenderer.php @@ -146,7 +146,7 @@ private function renderButton(CommandInterface $command) $buttonEvent ->setAccessKey(isset($extra['accesskey']) ? \trim($extra['accesskey']) : '') ->setAttributes(' ' . \ltrim($extra['attributes'] ?? '')) - ->setClass($extra['class']) + ->setClass($extra['class'] ?? '') ->setKey($command->getName()) ->setHref($href) ->setLabel($label) diff --git a/src/Contao/View/Contao2BackendView/Subscriber/CheckPermission.php b/src/Contao/View/Contao2BackendView/Subscriber/CheckPermission.php index 89011350a..6622be542 100644 --- a/src/Contao/View/Contao2BackendView/Subscriber/CheckPermission.php +++ b/src/Contao/View/Contao2BackendView/Subscriber/CheckPermission.php @@ -21,6 +21,7 @@ namespace ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Subscriber; +use Contao\CoreBundle\Security\ContaoCorePermissions; use ContaoCommunityAlliance\DcGeneral\Contao\DataDefinition\Definition\Contao2BackendViewDefinitionInterface; use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator; use ContaoCommunityAlliance\DcGeneral\DataDefinition\Definition\View\CommandCollectionInterface; @@ -30,6 +31,7 @@ use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\PropertyInterface; use ContaoCommunityAlliance\DcGeneral\Factory\Event\BuildDataDefinitionEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Security\Core\Security; /** * The check permission subscriber. @@ -48,7 +50,10 @@ class CheckPermission implements EventSubscriberInterface * * @param RequestScopeDeterminator $scopeDeterminator */ - public function __construct(RequestScopeDeterminator $scopeDeterminator) + public function __construct( + RequestScopeDeterminator $scopeDeterminator, + private Security $security + ) { $this->scopeDeterminator = $scopeDeterminator; } @@ -84,6 +89,7 @@ public function checkPermissionForProperties(BuildDataDefinitionEvent $event) $container = $event->getContainer(); $properties = $container->getPropertiesDefinition(); $palettesDefinition = $container->getPalettesDefinition(); + $definitionName = $container->getName(); foreach ($palettesDefinition->getPalettes() as $palette) { foreach ($palette->getProperties() as $property) { @@ -100,10 +106,15 @@ public function checkPermissionForProperties(BuildDataDefinitionEvent $event) // @codingStandardsIgnoreEnd continue; } + $excluded = $properties->getProperty($name)->isExcluded(); + // Include all excluded fields which are allowed for the current user + if ($excluded && $this->security->isGranted(ContaoCorePermissions::USER_CAN_EDIT_FIELD_OF_TABLE, $definitionName . '::' . $name)) { + $excluded = false; + } $this ->getVisibilityConditionChain($property) - ->addCondition(new BooleanCondition(!$properties->getProperty($name)->isExcluded())); + ->addCondition(new BooleanCondition(!$excluded)); } } } diff --git a/src/Contao/View/Contao2BackendView/Subscriber/WidgetBuilder.php b/src/Contao/View/Contao2BackendView/Subscriber/WidgetBuilder.php index ea4617d7c..a3303beec 100644 --- a/src/Contao/View/Contao2BackendView/Subscriber/WidgetBuilder.php +++ b/src/Contao/View/Contao2BackendView/Subscriber/WidgetBuilder.php @@ -547,12 +547,18 @@ private function prepareWidgetAttributes(ModelInterface $model, PropertyInterfac $propExtra = $this->setPropExtraDisabled($property, $propExtra); + // If no description present, pass as string instead of array. + $label = $this->translator->trans($property->getLabel(), [], $defName); + if ('' !== $description = $property->getDescription()) { + $label = [ + $label, + $this->translator->trans($description, [], $defName), + ]; + } + $widgetConfig = [ 'inputType' => $property->getWidgetType(), - 'label' => [ - $this->translator->trans($property->getLabel(), [], $defName), - $this->translator->trans($property->getDescription(), [], $defName), - ], + 'label' => $label, 'options' => $this->getOptionsForWidget($property, $model), 'eval' => $propExtra, ]; diff --git a/src/Contao/View/Contao2BackendView/ViewHelpers.php b/src/Contao/View/Contao2BackendView/ViewHelpers.php index ac64737ee..3395cf806 100644 --- a/src/Contao/View/Contao2BackendView/ViewHelpers.php +++ b/src/Contao/View/Contao2BackendView/ViewHelpers.php @@ -3,7 +3,7 @@ /** * This file is part of contao-community-alliance/dc-general. * - * (c) 2013-2023 Contao Community Alliance. + * (c) 2013-2024 Contao Community Alliance. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,13 +17,14 @@ * @author Stefan Heimes * @author Sven Baumann * @author Ingolf Steinhardt - * @copyright 2013-2023 Contao Community Alliance. + * @copyright 2013-2024 Contao Community Alliance. * @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ namespace ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView; +use Contao\System; use ContaoCommunityAlliance\Contao\Bindings\ContaoEvents; use ContaoCommunityAlliance\Contao\Bindings\Events\Controller\RedirectEvent; use ContaoCommunityAlliance\DcGeneral\Contao\DataDefinition\Definition\Contao2BackendViewDefinitionInterface; @@ -40,7 +41,14 @@ use ContaoCommunityAlliance\DcGeneral\Panel\PanelInterface; use ContaoCommunityAlliance\DcGeneral\Panel\SortElementInterface; use ContaoCommunityAlliance\DcGeneral\View\Event\RenderReadablePropertyValueEvent; +use LogicException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + +use function sprintf; +use function strtoupper; /** * Helper class that provides static methods used in views. @@ -157,7 +165,7 @@ public static function initializeSorting($panel, $dataConfig, $listingConfig) $newSorting = []; foreach ($listingConfig->getGroupAndSortingDefinition()->getDefault() as $information) { /** @var GroupAndSortingInformationInterface $information */ - $newSorting[$information->getProperty()] = \strtoupper($information->getSortingMode()); + $newSorting[$information->getProperty()] = strtoupper($information->getSortingMode()); } $dataConfig->setSorting($newSorting); } @@ -240,44 +248,75 @@ public static function getReadableFieldValue( * * @param EnvironmentInterface $environment The environment. * - * @return void + * @return never */ - public static function redirectHome(EnvironmentInterface $environment) + public static function redirectHome(EnvironmentInterface $environment): never { $input = $environment->getInputProvider(); assert($input instanceof InputProviderInterface); + $request = self::getRequest(); + $routeName = $request->attributes->get('_route'); + if ($routeName !== 'contao.backend') { + self::determineNewStyleRedirect($routeName, $request, $environment); + } + if ($input->hasParameter('table')) { if ($input->hasParameter('pid')) { $event = new RedirectEvent( - \sprintf( + sprintf( 'contao?do=%s&table=%s&pid=%s', $input->getParameter('do'), $input->getParameter('table'), $input->getParameter('pid') ) ); - } else { - $event = new RedirectEvent( - \sprintf( - 'contao?do=%s&table=%s', - $input->getParameter('do'), - $input->getParameter('table') - ) - ); + self::dispatchRedirect($environment, $event); } - } else { $event = new RedirectEvent( - \sprintf( - 'contao?do=%s', - $input->getParameter('do') + sprintf( + 'contao?do=%s&table=%s', + $input->getParameter('do'), + $input->getParameter('table') ) ); + self::dispatchRedirect($environment, $event); } + $event = new RedirectEvent(sprintf('contao?do=%s', $input->getParameter('do'))); + + self::dispatchRedirect($environment, $event); + } + private static function determineNewStyleRedirect( + string $routeName, + Request $request, + EnvironmentInterface $environment + ): never + { + $routeGenerator = System::getContainer()->get('router'); + assert($routeGenerator instanceof UrlGeneratorInterface); + $parameters = $request->query->all(); + unset($parameters['act']); + $routeBase = $routeGenerator->generate($routeName, $parameters); + + self::dispatchRedirect($environment, new RedirectEvent($routeBase)); + } + + private static function getRequest(): Request + { + $requestStack = System::getContainer()->get('request_stack'); + assert($requestStack instanceof RequestStack); + + return $requestStack->getCurrentRequest(); + } + + public static function dispatchRedirect(EnvironmentInterface $environment, RedirectEvent $event): never + { $dispatcher = $environment->getEventDispatcher(); assert($dispatcher instanceof EventDispatcherInterface); $dispatcher->dispatch($event, ContaoEvents::CONTROLLER_REDIRECT); + + throw new LogicException('Redirect did not happen.'); } } diff --git a/src/DataDefinition/Definition/View/BackCommand.php b/src/DataDefinition/Definition/View/BackCommand.php index e64d04689..6faa5ac23 100644 --- a/src/DataDefinition/Definition/View/BackCommand.php +++ b/src/DataDefinition/Definition/View/BackCommand.php @@ -31,7 +31,7 @@ class BackCommand extends Command public function __construct() { parent::__construct(); - $this->extra['class'] = 'header_back'; + $this->extra['class'] = 'header_back dcgBC'; $this->extra['accesskey'] = 'b'; $this->extra['attributes'] = 'onclick="Backend.getScrollOffset();"'; $this diff --git a/src/DataDefinition/Definition/View/CreateModelCommand.php b/src/DataDefinition/Definition/View/CreateModelCommand.php index f66c6f5fd..9fad2c4f6 100644 --- a/src/DataDefinition/Definition/View/CreateModelCommand.php +++ b/src/DataDefinition/Definition/View/CreateModelCommand.php @@ -3,7 +3,7 @@ /** * This file is part of contao-community-alliance/dc-general. * - * (c) 2013-2019 Contao Community Alliance. + * (c) 2013-2024 Contao Community Alliance. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,7 +13,8 @@ * @package contao-community-alliance/dc-general * @author Christian Schiffler * @author Sven Baumann - * @copyright 2013-2019 Contao Community Alliance. + * @author Ingolf Steinhardt + * @copyright 2013-2024 Contao Community Alliance. * @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -36,8 +37,8 @@ public function __construct() $this->extra['attributes'] = 'onclick="Backend.getScrollOffset();"'; $this ->setName('button_new') - ->setLabel('new.0') - ->setDescription('new.1'); + ->setLabel('new.label') + ->setDescription('new.description'); $this->parameters['act'] = 'create'; } } diff --git a/src/EventListener/StoreRefererListener.php b/src/EventListener/StoreRefererListener.php new file mode 100644 index 000000000..1b57b72a7 --- /dev/null +++ b/src/EventListener/StoreRefererListener.php @@ -0,0 +1,132 @@ + + * @author Ingolf Steinhardt + * @copyright 2013-2024 Contao Community Alliance. + * @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later + * @filesource + */ + +declare(strict_types=1); + +namespace ContaoCommunityAlliance\DcGeneral\EventListener; + +use Contao\CoreBundle\Routing\ScopeMatcher; +use Contao\User; +use RuntimeException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\Security\Core\Security; + +use function array_merge; +use function array_shift; +use function count; +use function is_array; +use function strlen; + +/** + * @internal + */ +class StoreRefererListener +{ + public function __construct( + private readonly Security $security, + private readonly ScopeMatcher $scopeMatcher + ) { + } + + /** + * Stores the referer in the session. + */ + public function __invoke(ResponseEvent $event): void + { + if (!$this->scopeMatcher->isBackendMainRequest($event)) { + return; + } + + $request = $event->getRequest(); + if (!$request->isMethod(Request::METHOD_GET)) { + return; + } + + $response = $event->getResponse(); + if (200 !== $response->getStatusCode()) { + return; + } + + $user = $this->security->getUser(); + if (!$user instanceof User) { + return; + } + + if (!$this->canModifyBackendSession($request)) { + return; + } + + if (!$request->hasSession()) { + throw new RuntimeException('The request did not contain a session.'); + } + + $session = $request->getSession(); + $key = $request->query->has('popup') ? 'popupReferer' : 'referer'; + $refererId = $request->attributes->get('_contao_referer_id'); + $referers = $this->prepareBackendReferer($refererId, $session->get($key)); + $ref = $request->query->get('ref', ''); + + // Move current to last if the referer is in both the URL and the session. + if ('' !== $ref && isset($referers[$ref])) { + $referers[$refererId] = array_merge($referers[$ref], $referers[$refererId]); + $referers[$refererId]['last'] = $referers[$ref]['current']; + } + + // Set new current referer + $referers[$refererId]['current'] = $this->getRelativeRequestUri($request); + + $session->set($key, $referers); + } + + private function canModifyBackendSession(Request $request): bool + { + return true === $request->attributes->get('_dcg_referer_update') && !$request->isXmlHttpRequest(); + } + + /** + * @return array> + */ + private function prepareBackendReferer(string $refererId, array $referers = null): array + { + if (!is_array($referers)) { + $referers = []; + } + + if (!isset($referers[$refererId]) || !is_array($referers[$refererId])) { + $referers[$refererId] = end($referers) ?: ['last' => '']; + } + + // Make sure we never have more than 25 different referer URLs + while (count($referers) >= 25) { + array_shift($referers); + } + + return $referers; + } + + /** + * Returns the current request URI relative to the base path. + */ + private function getRelativeRequestUri(Request $request): string + { + return (string) substr($request->getRequestUri(), strlen($request->getBasePath()) + 1); + } +} diff --git a/src/Resources/config/backend_event_subscribers.yml b/src/Resources/config/backend_event_subscribers.yml index 2be544dfb..0a591669d 100644 --- a/src/Resources/config/backend_event_subscribers.yml +++ b/src/Resources/config/backend_event_subscribers.yml @@ -36,6 +36,7 @@ services: public: true arguments: - "@cca.dc-general.scope-matcher" + - "@security.helper" tags: - name: kernel.event_subscriber diff --git a/src/Resources/config/contao/handler_backend_listeners.yml b/src/Resources/config/contao/handler_backend_listeners.yml index 7d8120695..bc6055d33 100644 --- a/src/Resources/config/contao/handler_backend_listeners.yml +++ b/src/Resources/config/contao/handler_backend_listeners.yml @@ -27,6 +27,8 @@ services: arguments: - "@cca.dc-general.scope-matcher" - "@cca.dc-general.security-url-builder-factory" + - "@request_stack" + - "@router" tags: - name: kernel.event_listener event: dc-general.action diff --git a/src/Resources/config/event_listeners.yml b/src/Resources/config/event_listeners.yml index 55fb9e8b6..763a19c9f 100644 --- a/src/Resources/config/event_listeners.yml +++ b/src/Resources/config/event_listeners.yml @@ -61,3 +61,10 @@ services: - name: kernel.event_listener event: dc-general.model.post-paste priority: -256 + + ContaoCommunityAlliance\DcGeneral\EventListener\StoreRefererListener: + arguments: + - '@security.helper' + - '@contao.routing.scope_matcher' + tags: + - kernel.event_listener diff --git a/src/Resources/contao/templates/dcbe_general_show.html5 b/src/Resources/contao/templates/dcbe_general_show.html5 index 636205c5c..af7fd12a9 100644 --- a/src/Resources/contao/templates/dcbe_general_show.html5 +++ b/src/Resources/contao/templates/dcbe_general_show.html5 @@ -15,7 +15,7 @@ assert($translator instanceof \Symfony\Contracts\Translation\TranslatorInterface ?> diff --git a/src/Resources/public/css/generalDriver.css b/src/Resources/public/css/generalDriver.css index bbb2f6eb4..74e3ef635 100644 --- a/src/Resources/public/css/generalDriver.css +++ b/src/Resources/public/css/generalDriver.css @@ -1,2 +1,2 @@ @charset "UTF-8";@media projection,screen{div table.tl_listing{margin-top:0!important;margin-bottom:0!important}.tl_folder_tlist{border-top:0}.treepicker_popup a.folding{float:left;margin-right:20px}.tl_listing tr.tl_folder_clipped>td{background-color:#fff9e6}.cursor_disabled{cursor:not-allowed}#dcg_clipboard{position:relative;padding-top:2px;padding-left:40px;min-height:32px;background-image:url(../images/clipboard.svg);background-size:24px 24px;background-position:6px 3px;background-repeat:no-repeat}#dcg_clipboard .btn-clear{position:absolute;top:3px;left:6px;opacity:0;-webkit-transition:opacity 300ms;transition:opacity 300ms}#dcg_clipboard .btn-clear:hover{opacity:1;-webkit-transition:opacity 300ms;transition:opacity 300ms}#dcg_clipboard ul{display:block}#dcg_clipboard li{display:inline-block;border:1px solid #ddd;background-color:#f9f9f9;padding:2px 4px}#dcg_clipboard li>*{display:inline-block;vertical-align:middle}#dcg_clipboard img{vertical-align:middle}.tl_language_panel{padding:6px 6px 7px 0;background:#f3f3f3;border-top:1px solid #fff;border-bottom:1px solid #bbb;text-align:right}.tl_language_panel .tl_select{width:240px}.mac .tl_language_panel select{max-width:none}.mac .tl_language_panel .tl_select,.mac .tl_panel_bottom .tl_select{font-size:11px}.ie .tl_language_panel,.safari .tl_language_panel{overflow:hidden}.tl_language_panel .tl_formbody{position:relative}.ie .tl_language_panel .tl_formbody,.safari .tl_language_panel .tl_formbody{float:right}.tl_language_panel .tl_submit{margin-top:3px;vertical-align:top}.ie .tl_language_panel .tl_submit,.webkit .tl_language_panel .tl_submit{padding-top:4px;padding-bottom:4px}.opera .tl_language_panel .tl_submit{padding-top:3px;padding-bottom:3px;margin-top:-1px}.tl_language_panel img{position:relative;top:4px;vertical-align:top}#general_messageBox{width:-webkit-min-content;width:-moz-min-content;width:min-content;max-width:60%;min-width:40%;padding:24px;position:absolute;left:0;right:0;margin:0 auto;background:#fff no-repeat right center;border:2px solid #666;border-radius:6px;font-family:"Trebuchet MS",Verdana,sans-serif;font-size:15px;text-align:left;word-wrap:break-word}#general_messageBox.loading{background-image:url(../images/loading.gif);padding-right:60px}#general_messageBox.box-small{width:-webkit-max-content;width:-moz-max-content;width:max-content}#general_messageBox .tl_submit{text-align:center}#general_messageBox .tl_submit_container{text-align:right}#general_messageBox .tl_submit_container [type=submit]{margin-left:4px}.stickySave #general_messageBox .tl_submit_container{text-align:right;position:relative}.stickySave #general_messageBox .tl_submit_container [type=submit]{margin-left:4px}#general_messageOverlay{width:-webkit-max-content;width:-moz-max-content;width:max-content;height:100%;position:absolute;top:0;left:0;background:#fff;opacity:0.5}.header_stop{background-image:url("/system/themes/flexible/icons/stop.svg");background-size:16px}} -/*# sourceMappingURL=generalDriver.css.map */ +/*# sourceMappingURL=generalDriver.css.map */ \ No newline at end of file diff --git a/src/Resources/public/css/generalDriver.css.map b/src/Resources/public/css/generalDriver.css.map index 298a3c537..404a81146 100644 --- a/src/Resources/public/css/generalDriver.css.map +++ b/src/Resources/public/css/generalDriver.css.map @@ -1 +1 @@ -{"version":3,"sources":["generalDriver.css","../sass/generalDriver.scss","../sass/_clipboard.scss","../sass/_languagePanel.scss","../sass/_messageBox.scss","../sass/_headerButton.scss"],"names":[],"mappings":"AAAA,gBAAgB,CCUhB,yBACE,qBACE,sBAAA,CACA,yBDCF,CCEA,iBACE,YDCF,CCEA,4BACE,UAAA,CACA,iBDCF,CCEA,oCACE,wBDCF,CCEA,iBACE,kBDCF,CE/BF,eACE,iBAAA,CACA,eAAA,CACA,iBAAA,CACA,eAAA,CACA,6CAAA,CACA,yBAAA,CACA,2BAAA,CACA,2BFkCA,CEhCA,0BACE,iBAAA,CACA,OAAA,CACA,QAAA,CACA,SAAA,CACA,gCAAA,CAAA,wBFkCF,CEhCE,gCACE,SAAA,CACA,gCAAA,CAAA,wBFkCJ,CE/BA,kBACE,aFiCF,CE/BA,kBACE,oBAAA,CACA,qBAAA,CACA,wBAAA,CACA,eFiCF,CE/BE,oBACE,oBAAA,CACA,qBFiCJ,CE9BA,mBACE,qBFgCF,CGrEF,mBACE,qBAAA,CACA,kBAAA,CACA,yBAAA,CACA,4BAAA,CACA,gBHwEA,CGrEF,8BACE,WHwEA,CGrEF,+BACE,cHwEA,CGrEF,oEAEE,cHwEA,CGrEF,kDAEE,eHwEA,CGrEF,gCACE,iBHwEA,CGrEF,4EAEE,WHwEA,CGrEF,8BACE,cAAA,CACA,kBHwEA,CGrEF,wEAEE,eAAA,CACA,kBHwEA,CGrEF,qCACE,eAAA,CACA,kBAAA,CACA,eHwEA,CGrEF,uBACE,iBAAA,CACA,OAAA,CACA,kBHwEA,CI/HF,oBACE,yBAAA,CAAA,sBAAA,CAAA,iBAAA,CACA,aAAA,CACA,aAAA,CACA,YAAA,CACA,iBAAA,CACA,MAAA,CACA,OAAA,CACA,aAAA,CACA,sCAAA,CACA,qBAAA,CACA,iBAAA,CACA,6CAAA,CACA,cAAA,CACA,eAAA,CACA,oBJkIA,CIhIA,4BACE,2CAAA,CACA,kBJkIF,CI/HA,8BACE,yBAAA,CAAA,sBAAA,CAAA,iBJiIF,CI9HA,+BACE,iBJgIF,CI7HA,yCACE,gBJ+HF,CI7HE,uDACE,eJ+HJ,CIzHF,qDACE,gBAAA,CACA,iBJ6HA,CI3HA,mEACE,eJ6HF,CIzHF,wBACE,yBAAA,CAAA,sBAAA,CAAA,iBAAA,CACA,WAAA,CACA,iBAAA,CACA,KAAA,CACA,MAAA,CACA,eAAA,CACA,WJ4HA,CKpLF,aACE,8DAAA,CACA,oBLuLA,CACF","file":"generalDriver.css"} \ No newline at end of file +{"version":3,"sources":["generalDriver.css","../sass/generalDriver.scss","../sass/_clipboard.scss","../sass/_languagePanel.scss","../sass/_messageBox.scss","../sass/_headerButton.scss"],"names":[],"mappings":"AAAA,gBAAgB,CCUhB,yBACE,qBACE,sBAAA,CACA,yBDCF,CCEA,iBACE,YDAF,CCGA,4BACE,UAAA,CACA,iBDDF,CCIA,oCACE,wBDFF,CCKA,iBACE,kBDHF,CE3BF,eACE,iBAAA,CACA,eAAA,CACA,iBAAA,CACA,eAAA,CACA,6CAAA,CACA,yBAAA,CACA,2BAAA,CACA,2BF6BA,CE3BA,0BACE,iBAAA,CACA,OAAA,CACA,QAAA,CACA,SAAA,CACA,gCAAA,CAAA,wBF6BF,CE3BE,gCACE,SAAA,CACA,gCAAA,CAAA,wBF6BJ,CE1BA,kBACE,aF4BF,CE1BA,kBACE,oBAAA,CACA,qBAAA,CACA,wBAAA,CACA,eF4BF,CE1BE,oBACE,oBAAA,CACA,qBF4BJ,CEzBA,mBACE,qBF2BF,CGhEF,mBACE,qBAAA,CACA,kBAAA,CACA,yBAAA,CACA,4BAAA,CACA,gBHkEA,CG/DF,8BACE,WHiEA,CG9DF,+BACE,cHgEA,CG7DF,oEAEE,cH+DA,CG5DF,kDAEE,eH8DA,CG3DF,gCACE,iBH6DA,CG1DF,4EAEE,WH4DA,CGzDF,8BACE,cAAA,CACA,kBH2DA,CGxDF,wEAEE,eAAA,CACA,kBH0DA,CGvDF,qCACE,eAAA,CACA,kBAAA,CACA,eHyDA,CGtDF,uBACE,iBAAA,CACA,OAAA,CACA,kBHwDA,CI/GF,oBACE,yBAAA,CAAA,sBAAA,CAAA,iBAAA,CACA,aAAA,CACA,aAAA,CACA,YAAA,CACA,iBAAA,CACA,MAAA,CACA,OAAA,CACA,aAAA,CACA,sCAAA,CACA,qBAAA,CACA,iBAAA,CACA,6CAAA,CACA,cAAA,CACA,eAAA,CACA,oBJiHA,CI/GA,4BACE,2CAAA,CACA,kBJiHF,CI9GA,8BACE,yBAAA,CAAA,sBAAA,CAAA,iBJgHF,CI7GA,+BACE,iBJ+GF,CI5GA,yCACE,gBJ8GF,CI5GE,uDACE,eJ8GJ,CIxGF,qDACE,gBAAA,CACA,iBJ2GA,CIzGA,mEACE,eJ2GF,CIvGF,wBACE,yBAAA,CAAA,sBAAA,CAAA,iBAAA,CACA,WAAA,CACA,iBAAA,CACA,KAAA,CACA,MAAA,CACA,eAAA,CACA,WJyGA,CKjKF,aACE,8DAAA,CACA,oBLmKA,CACF","file":"generalDriver.css"} \ No newline at end of file diff --git a/src/Resources/public/js/vanillaGeneral.js b/src/Resources/public/js/vanillaGeneral.js index e311ad0c6..d920677c9 100644 --- a/src/Resources/public/js/vanillaGeneral.js +++ b/src/Resources/public/js/vanillaGeneral.js @@ -157,7 +157,7 @@ function GeneralTableDnD() // Build url. var href = window.location.href.replace(/\?.*$/, ''); - var req = window.location.search; + var req = window.location.search + '?'; req += '&act=paste'; req += '&source=' + id; req += '&after=' + insertAfter; diff --git a/src/Resources/public/sass/generalDriver.scss b/src/Resources/public/sass/generalDriver.scss index b0197935e..ded539c3f 100644 --- a/src/Resources/public/sass/generalDriver.scss +++ b/src/Resources/public/sass/generalDriver.scss @@ -26,10 +26,10 @@ .tl_listing tr.tl_folder_clipped > td { background-color: #fff9e6; } - + .cursor_disabled{ cursor: not-allowed; - } + } @import "clipboard"; @import "languagePanel"; diff --git a/src/Resources/translations/dc-general.de.xlf b/src/Resources/translations/dc-general.de.xlf index ac284dff2..fe2c7e12a 100644 --- a/src/Resources/translations/dc-general.de.xlf +++ b/src/Resources/translations/dc-general.de.xlf @@ -1,465 +1,471 @@ - - - - Language - Sprache - - - - - Switch language - Sprache wechseln - - - - - Table: %table% - Tabelle: %table% - - - - - The property "%property%" is already in the database and not unique. - Die Eigenschaft "%property%" ist schon in der Datenbank und nicht unique. - - - - - Nothing was selected! - Es wurde nichts ausgewählt! - - - - - Ok - Ok - - - - - Abort - Abbrechen - - - - - Cancel - Beenden - - - - - Cancel multiple processing. - Die Mehrfachbearbeitung beenden. - - - - - The property "%property%" isn't supported in mode "%mode%". - Die Eigenschaft "%property%" wird im Modus "%mode%" nicht unterstützt. - - - - - You must select the property "%property%" for edit it. - Die Eigenschaft "%property%" muss ausgewählt sein, damit diese bearbeitet werden kann. - - - - - You must select the parent property "%parent_property%" for edit the property - "%edit_property%". - - Die Abhängige Eigenschaft "%parent_property%" muss ausgewählt sein, damit man die Eigenschaft - "%edit_property%" bearbeiten kann. - - - - - - Select properties - Eigenschaften auswählen - - - - - Please check your selected properties! - Bitte überprüfen Sie die ausgewählten Eigenschaften! - - - - - Select models - Elemente auswählen - - - - - Disabled: %title% - Gesperrt: %title% - - - - - Create a new item - Neuen Datensatz erstellen - - - - - Edit record %id% - Datensatz %id% bearbeiten - - - - - W Y - W. Y - - - - - Delete - Löschen - - - - - Edit - Bearbeiten - - - - - Override - Überschreiben - - - - - Copy - Kopieren - - - - - Close - Schließen - - - - - Continue - Weiter - - - - - Do you really want to delete the selected records? - Wollen Sie die ausgewählten Einträge wirklich löschen? - - - - - Delete - Löschen - - - - - Move - Verschieben - - - - - Copy - Kopieren - - - - - Edit - Bearbeiten - - - - - Override - Überschreiben - - - - - Edit multiple - Mehrere bearbeiten - - - - - no - nein - - - - - yes - ja - - - - - Show the details of record %id% - Details des Datensatzes %id% anzeigen - - - - - Color picker - Farbe auswählen - - - - - Word wrap - Zeilenumbruch - - - - - Open the help wizard - Den Hilfe-Assistent aufrufen - - - - - Change selection - Auswahl ändern - - - - - Drag the items to re-order them - Elemente können durch Ziehen umsortiert werden - - - - - Reset selection - Auswahl aufheben - - - - - Select all - Alle auswählen - - - - - Collapse node - Bereich schließen - - - - - Expand node - Bereich öffnen - - - - - Save - Speichern - - - - - Save and close - Speichern und schließen - - - - - Save and edit - Speichern und bearbeiten - - - - - Save and go back - Speichern und zurück - - - - - Save and new - Speichern und neu - - - - - Save and duplicate - Speichern und duplizieren - - - - - Go back - Zurück - - - - - Back to the previous page - Zurück zur vorherigen Seite - - - - - Revision date - Änderungsdatum - - - - - 0 - 1 - - - - - %B %d%o, %Y - %d. %B %Y - - - - - ID - ID - - - - - Parent ID - Elternelement - - - - - Sorting value - Sortierindex - - - - - Search - Suchen - - - - - Treepicker manager - Treepicker-Manager - - - - - utf-8 - utf-8 - - - - - Records - Datensätze - - - - - All - Alle - - - - - Update mode - Update-Modus - - - - - Add the selected values - Ausgewählte Werte hinzufügen - - - - - Remove the selected values - Ausgewählte Werte entfernen - - - - - Replace the existing entries - Bestehende Einträge überschreiben - - - - - Apply - Anwenden - - - - - Sort - Sortieren - - - - - Show - Anzeigen - - - - - Reset - Zurücksetzen - - - - - Version - Version - - - - - Restore - Wiederherstellen - - - - - Clear clipboard - Ablage leeren - - - - - Remove this item from clipboard - Element von Ablage entfernen - - - - - No records found. - Keine Einträge gefunden. - - - + + + + Language + Sprache + + + + + Switch language + Sprache wechseln + + + + + Table: %table% + Tabelle: %table% + + + + + Color picker + Farbe auswählen + + + + + Page picker + Seite auswählen + + + + + The property "%property%" is already in the database and not unique. + Die Eigenschaft "%property%" ist schon in der Datenbank und nicht unique. + + + + + Nothing was selected! + Es wurde nichts ausgewählt! + + + + + Ok + Ok + + + + + Abort + Abbrechen + + + + + Cancel + Beenden + + + + + Cancel multiple processing. + Die Mehrfachbearbeitung beenden. + + + + + The property "%property%" isn't supported in mode "%mode%". + Die Eigenschaft "%property%" wird im Modus "%mode%" nicht unterstützt. + + + + + You must select the property "%property%" for edit it. + Die Eigenschaft "%property%" muss ausgewählt sein, damit diese bearbeitet werden kann. + + + + + You must select the parent property "%parent_property%" for edit the property + "%edit_property%". + + Die Abhängige Eigenschaft "%parent_property%" muss ausgewählt sein, damit man die Eigenschaft + "%edit_property%" bearbeiten kann. + + + + + + Select properties + Eigenschaften auswählen + + + + + Please check your selected properties! + Bitte überprüfen Sie die ausgewählten Eigenschaften! + + + + + Select models + Elemente auswählen + + + + + Disabled: %title% + Gesperrt: %title% + + + + + Create a new item + Neuen Datensatz erstellen + + + + + Edit record %id% + Datensatz %id% bearbeiten + + + + + W Y + W. Y + + + + + Delete + Löschen + + + + + Edit + Bearbeiten + + + + + Override + Überschreiben + + + + + Copy + Kopieren + + + + + Close + Schließen + + + + + Continue + Weiter + + + + + Do you really want to delete the selected records? + Wollen Sie die ausgewählten Einträge wirklich löschen? + + + + + Delete + Löschen + + + + + Move + Verschieben + + + + + Copy + Kopieren + + + + + Edit + Bearbeiten + + + + + Override + Überschreiben + + + + + Edit multiple + Mehrere bearbeiten + + + + + no + nein + + + + + yes + ja + + + + + Show the details of record %id% + Details des Datensatzes %id% anzeigen + + + + + Word wrap + Zeilenumbruch + + + + + Open the help wizard + Den Hilfe-Assistent aufrufen + + + + + Change selection + Auswahl ändern + + + + + Drag the items to re-order them + Elemente können durch Ziehen umsortiert werden + + + + + Reset selection + Auswahl aufheben + + + + + Select all + Alle auswählen + + + + + Collapse node + Bereich schließen + + + + + Expand node + Bereich öffnen + + + + + Save + Speichern + + + + + Save and close + Speichern und schließen + + + + + Save and edit + Speichern und bearbeiten + + + + + Save and go back + Speichern und zurück + + + + + Save and new + Speichern und neu + + + + + Save and duplicate + Speichern und duplizieren + + + + + Go back + Zurück + + + + + Back to the previous page + Zurück zur vorherigen Seite + + + + + Revision date + Änderungsdatum + + + + + 0 + 1 + + + + + %B %d%o, %Y + %d. %B %Y + + + + + ID + ID + + + + + Parent ID + Elternelement + + + + + Sorting value + Sortierindex + + + + + Search + Suchen + + + + + Treepicker manager + Treepicker-Manager + + + + + utf-8 + utf-8 + + + + + Records + Datensätze + + + + + All + Alle + + + + + Update mode + Update-Modus + + + + + Add the selected values + Ausgewählte Werte hinzufügen + + + + + Remove the selected values + Ausgewählte Werte entfernen + + + + + Replace the existing entries + Bestehende Einträge überschreiben + + + + + Apply + Anwenden + + + + + Sort + Sortieren + + + + + Show + Anzeigen + + + + + Reset + Zurücksetzen + + + + + Version + Version + + + + + Restore + Wiederherstellen + + + + + Clear clipboard + Ablage leeren + + + + + Remove this item from clipboard + Element von Ablage entfernen + + + + + No records found. + Keine Einträge gefunden. + + + diff --git a/src/Resources/translations/dc-general.en.xlf b/src/Resources/translations/dc-general.en.xlf index 22ab9d8a8..c475f7746 100644 --- a/src/Resources/translations/dc-general.en.xlf +++ b/src/Resources/translations/dc-general.en.xlf @@ -1,387 +1,391 @@ - - - - Language - - - - - Switch language - - - - - Table: %table% - - - - - The property "%property%" is already in the database and not unique. - - - - - Nothing was selected! - - - - - Ok - - - - - Abort - - - - - Cancel - - - - - Cancel multiple processing. - - - - - The property "%property%" isn't supported in mode "%mode%". - - - - - You must select the property "%property%" for edit it. - - - - - You must select the parent property "%parent_property%" for edit the property - "%edit_property%". - - - - - - Select properties - - - - - Please check your selected properties! - - - - - Select models - - - - - Disabled: %title% - - - - - Create a new item - - - - - Edit record %id% - - - - - W Y - - - - - Delete - - - - - Edit - - - - - Override - - - - - Copy - - - - - Close - - - - - Continue - - - - - Do you really want to delete the selected records? - - - - - Delete - - - - - Move - - - - - Copy - - - - - Edit - - - - - Override - - - - - Edit multiple - - - - - no - - - - - yes - - - - - Show the details of record %id% - - - - - Color picker - - - - - Word wrap - - - - - Open the help wizard - - - - - Change selection - - - - - Drag the items to re-order them - - - - - Reset selection - - - - - Select all - - - - - Collapse node - - - - - Expand node - - - - - Save - - - - - Save and close - - - - - Save and edit - - - - - Save and go back - - - - - Save and new - - - - - Save and duplicate - - - - - Go back - - - - - Back to the previous page - - - - - Revision date - - - - - 0 - - - - - %B %d%o, %Y - - - - - ID - - - - - Parent ID - - - - - Sorting value - - - - - Search - - - - - Treepicker manager - - - - - utf-8 - - - - - Records - - - - - All - - - - - Update mode - - - - - Add the selected values - - - - - Remove the selected values - - - - - Replace the existing entries - - - - - Apply - - - - - Sort - - - - - Show - - - - - Reset - - - - - Version - - - - - Restore - - - - - Clear clipboard - - - - - Remove this item from clipboard - - - - - No records found. - - - + + + + Language + + + + + Switch language + + + + + Table: %table% + + + + + Color picker + + + + + Page picker + + + + + The property "%property%" is already in the database and not unique. + + + + + Nothing was selected! + + + + + Ok + + + + + Abort + + + + + Cancel + + + + + Cancel multiple processing. + + + + + The property "%property%" isn't supported in mode "%mode%". + + + + + You must select the property "%property%" to edit it. + + + + + You must select the parent property "%parent_property%" to edit the property "%edit_property%". + + + + + + Select properties + + + + + Please check your selected properties! + + + + + Select models + + + + + Disabled: %title% + + + + + Create a new item + + + + + Edit record %id% + + + + + W Y + + + + + Delete + + + + + Edit + + + + + Override + + + + + Copy + + + + + Close + + + + + Continue + + + + + Do you really want to delete the selected records? + + + + + Delete + + + + + Move + + + + + Copy + + + + + Edit + + + + + Override + + + + + Edit multiple + + + + + no + + + + + yes + + + + + Show the details of record %id% + + + + + Word wrap + + + + + Open the help wizard + + + + + Change selection + + + + + Drag the items to re-order them + + + + + Reset selection + + + + + Select all + + + + + Collapse node + + + + + Expand node + + + + + Save + + + + + Save and close + + + + + Save and edit + + + + + Save and go back + + + + + Save and new + + + + + Save and duplicate + + + + + Go back + + + + + Back to the previous page + + + + + Revision date + + + + + 0 + + + + + %B %d%o, %Y + + + + + ID + + + + + Parent ID + + + + + Sorting value + + + + + Search + + + + + Treepicker manager + + + + + utf-8 + + + + + Records + + + + + All + + + + + Update mode + + + + + Add the selected values + + + + + Remove the selected values + + + + + Replace the existing entries + + + + + Apply + + + + + Sort + + + + + Show + + + + + Reset + + + + + Version + + + + + Restore + + + + + Clear clipboard + + + + + Remove this item from clipboard + + + + + No records found. + + + diff --git a/src/View/ActionHandler/AbstractPropertyVisibilityHandler.php b/src/View/ActionHandler/AbstractPropertyVisibilityHandler.php index 5ac0e1563..0b7b6fe53 100644 --- a/src/View/ActionHandler/AbstractPropertyVisibilityHandler.php +++ b/src/View/ActionHandler/AbstractPropertyVisibilityHandler.php @@ -50,6 +50,7 @@ use function in_array; use function method_exists; use function sprintf; +use function Symfony\Component\DependencyInjection\Loader\Configurator\env; /** * This abstract visibility handler provide methods for the visibility of properties. @@ -498,7 +499,10 @@ protected function injectSelectSubPropertiesInformation( $information = []; foreach ($properties as $propertyName => $informationProperty) { - $label = !$informationProperty->getLabel() ? $propertyName : $informationProperty->getLabel(); + $label = $translator->translate( + $informationProperty->getLabel() ?: $propertyName, + $environment->getDataDefinition()?->getName() + ); $information[] = '

' .