From 9f2c573926e11dc33f9edde1de3984622e4de8a5 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Sun, 5 May 2024 20:03:43 +0200 Subject: [PATCH] Limit to 12.4.x --- Classes/Form/Element/PickColorFromImage.php | 116 ++++--- .../Form/Element/PickColorFromImagePre13.php | 304 ------------------ composer.json | 2 +- ext_localconf.php | 4 +- 4 files changed, 59 insertions(+), 367 deletions(-) mode change 100755 => 100644 Classes/Form/Element/PickColorFromImage.php delete mode 100644 Classes/Form/Element/PickColorFromImagePre13.php diff --git a/Classes/Form/Element/PickColorFromImage.php b/Classes/Form/Element/PickColorFromImage.php old mode 100755 new mode 100644 index e9e2e4e..8e95d84 --- a/Classes/Form/Element/PickColorFromImage.php +++ b/Classes/Form/Element/PickColorFromImage.php @@ -15,12 +15,8 @@ namespace Evoweb\EwBase\Form\Element; * LICENSE.txt file that was distributed with this source code. */ -use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Backend\Form\Element\AbstractFormElement; -use TYPO3\CMS\Backend\Form\Event\ModifyImageManipulationPreviewUrlEvent; -use TYPO3\CMS\Backend\Routing\UriBuilder; -use TYPO3\CMS\Backend\View\BackendViewFactory; -use TYPO3\CMS\Core\Crypto\HashService; +use TYPO3\CMS\Backend\Form\NodeFactory; use TYPO3\CMS\Core\Imaging\ImageManipulation\Area; use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection; use TYPO3\CMS\Core\Imaging\ImageManipulation\InvalidConfigurationException; @@ -31,11 +27,11 @@ use TYPO3\CMS\Core\Resource\ResourceFactory; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\MathUtility; use TYPO3\CMS\Core\Utility\StringUtility; +use TYPO3Fluid\Fluid\View\TemplateView; +use TYPO3Fluid\Fluid\View\ViewInterface; class PickColorFromImage extends AbstractFormElement { - private string $wizardRouteName = 'ajax_wizard_image_manipulation'; - /** * Default element configuration */ @@ -112,31 +108,53 @@ class PickColorFromImage extends AbstractFormElement ], ]; - public function __construct( - private readonly BackendViewFactory $backendViewFactory, - private readonly UriBuilder $uriBuilder, - private readonly EventDispatcherInterface $eventDispatcher, - private readonly ResourceFactory $resourceFactory, - private readonly HashService $hashService, - ) {} + protected ViewInterface $templateView; + + public function __construct(NodeFactory $nodeFactory, array $data) + { + parent::__construct($nodeFactory, $data); + // Would be great, if we could inject the view here, but since the constructor is in the interface, we can't + // @todo: It's unfortunate we're using Typo3Fluid TemplateView directly here. We can't + // inject BackendViewFactory here since __construct() is polluted by NodeInterface. + // Remove __construct() from NodeInterface to have DI, then use BackendViewFactory here. + $view = GeneralUtility::makeInstance(TemplateView::class); + $templatePaths = $view->getRenderingContext()->getTemplatePaths(); + $templatePaths + ->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:ew_base/Resources/Private/Templates')]); + $templatePaths + ->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:ew_base/Resources/Private/Partials')]); + $this->templateView = $view; + } - /** - * @throws InvalidConfigurationException - */ public function render(): array { $resultArray = $this->initializeResultArray(); $parameterArray = $this->data['parameterArray']; $config = $this->populateConfiguration($parameterArray['fieldConf']['config']); + $fieldId = StringUtility::getUniqueId('formengine-color-'); - $file = $this->getFile($this->data['databaseRow'], $config['imageField']); + $file = $this->getFileObject($this->data['databaseRow'], $config['imageField']); if (!$file) { + $languageService = $this->getLanguageService(); + $label = $languageService->sL( + 'LLL:EXT:ew_base/Resources/Private/Language/locallang_db.xlf:imageField.empty' + ); + $fieldLabel = $this->data['processedTca']['columns'][$config['imageField']]['label']; + $resultArray['html'] = ' +
+
+
+ + ' . sprintf($label, '' . $fieldLabel . '') . ' + +
+
+
+ '; // Early return in case we do not find a file return $resultArray; } - $config = $this->processConfiguration($config, $parameterArray['itemFormElValue'], $file); - $fieldInformationResult = $this->renderFieldInformation(); $fieldInformationHtml = $fieldInformationResult['html']; $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false); @@ -149,6 +167,14 @@ class PickColorFromImage extends AbstractFormElement $fieldWizardHtml = $fieldWizardResult['html']; $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false); + $width = $this->formMaxWidth( + MathUtility::forceIntegerInRange( + $config['size'] ?? $this->defaultInputWidth, + $this->minimumInputWidth, + $this->maxInputWidth + ) + ); + $arguments = [ 'fieldInformation' => $fieldInformationHtml, 'fieldControl' => $fieldControlHtml, @@ -167,15 +193,10 @@ class PickColorFromImage extends AbstractFormElement 'validation' => '[]', ], 'config' => $config, - 'wizardUri' => $this->getWizardUri(), - 'wizardPayload' => json_encode($this->getWizardPayload($config['cropVariants'], $file)), - 'previewUrl' => $this->eventDispatcher->dispatch( - new ModifyImageManipulationPreviewUrlEvent($this->data['databaseRow'], $config, $file) - )->getPreviewUrl(), + 'width' => $width, ]; if ($arguments['isAllowedFileExtension']) { - $fieldId = StringUtility::getUniqueId('formengine-color-'); $resultArray['stylesheetFiles'][] = 'EXT:ew_base/Resources/Public/JavaScript/form-engine/element/pick-color-from-image.css'; $resultArray['javaScriptModules'][] = JavaScriptModuleInstruction::create( @@ -191,14 +212,14 @@ class PickColorFromImage extends AbstractFormElement $arguments['formEngine']['validation'] = $this->getValidationDataAsJsonString(['required' => true]); } } - $view = $this->backendViewFactory->create($this->data['request']); - $view->assignMultiple($arguments); - $resultArray['html'] = $view->render('Form/ImageManipulationElement'); + + $this->templateView->assignMultiple($arguments); + $resultArray['html'] = $this->templateView->render('Form/ImageManipulationElement'); return $resultArray; } - protected function getFile(array $row, string $fieldName): ?File + protected function getFileObject(array $row, string $fieldName): ?File { $file = null; $fileUid = !empty($row[$fieldName]) ? $row[$fieldName] : null; @@ -207,26 +228,21 @@ class PickColorFromImage extends AbstractFormElement } if (MathUtility::canBeInterpretedAsInteger($fileUid)) { try { - $file = $this->resourceFactory->getFileObject($fileUid); + $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class); + $fileReference = $resourceFactory->getFileReferenceObject($fileUid); + $file = $fileReference->getOriginalFile(); } catch (FileDoesNotExistException | \InvalidArgumentException) { } } return $file; } - /** - * @throws InvalidConfigurationException - */ protected function populateConfiguration(array $baseConfiguration): array { $defaultConfig = self::$defaultConfig; - - // If ratios are set do not add default options - if (isset($baseConfiguration['cropVariants'])) { - unset($defaultConfig['cropVariants']); - } - $config = array_replace_recursive($defaultConfig, $baseConfiguration); + $imageConfig = $this->data['processedTca']['columns'][$config['imageField']]; + $config['cropVariants'] = $imageConfig['config']['cropVariants'] ?? $defaultConfig['cropVariants']; if (!is_array($config['cropVariants'])) { throw new InvalidConfigurationException('Crop variants configuration must be an array', 1485377267); @@ -264,8 +280,8 @@ class PickColorFromImage extends AbstractFormElement $config['cropVariants'] = $cropVariants; - // By default, we allow all image extensions that can be handled by the GFX functionality $config['allowedExtensions'] ??= $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']; + return $config; } @@ -283,22 +299,4 @@ class PickColorFromImage extends AbstractFormElement ); return $config; } - - protected function getWizardUri(): string - { - return (string)$this->uriBuilder->buildUriFromRoute($this->wizardRouteName); - } - - protected function getWizardPayload(array $cropVariants, File $image): array - { - $uriArguments = []; - $arguments = [ - 'cropVariants' => $cropVariants, - 'image' => $image->getUid(), - ]; - $uriArguments['arguments'] = json_encode($arguments); - $uriArguments['signature'] = $this->hashService->hmac((string)($uriArguments['arguments']), $this->wizardRouteName); - - return $uriArguments; - } } diff --git a/Classes/Form/Element/PickColorFromImagePre13.php b/Classes/Form/Element/PickColorFromImagePre13.php deleted file mode 100644 index ac81de5..0000000 --- a/Classes/Form/Element/PickColorFromImagePre13.php +++ /dev/null @@ -1,304 +0,0 @@ - 'image', - 'cropVariants' => [ - 'default' => [ - 'title' => - 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.crop_variant.default', - 'allowedAspectRatios' => [ - '16:9' => [ - 'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.16_9', - 'value' => 16 / 9, - ], - '3:2' => [ - 'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.3_2', - 'value' => 3 / 2, - ], - '4:3' => [ - 'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.4_3', - 'value' => 4 / 3, - ], - '1:1' => [ - 'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.1_1', - 'value' => 1.0, - ], - 'NaN' => [ - 'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.free', - 'value' => 0.0, - ], - ], - 'selectedRatio' => 'NaN', - 'cropArea' => [ - 'x' => 0.0, - 'y' => 0.0, - 'width' => 1.0, - 'height' => 1.0, - ], - ], - ], - ]; - - /** - * Default field information enabled for this element. - * - * @var array - */ - protected $defaultFieldInformation = [ - 'tcaDescription' => [ - 'renderType' => 'tcaDescription', - ], - ]; - - /** - * Default field wizards enabled for this element. - * - * @var array - */ - protected $defaultFieldWizard = [ - 'localizationStateSelector' => [ - 'renderType' => 'localizationStateSelector', - ], - 'otherLanguageContent' => [ - 'renderType' => 'otherLanguageContent', - 'after' => [ - 'localizationStateSelector', - ], - ], - 'defaultLanguageDifferences' => [ - 'renderType' => 'defaultLanguageDifferences', - 'after' => [ - 'otherLanguageContent', - ], - ], - ]; - - protected ViewInterface $templateView; - - public function __construct(NodeFactory $nodeFactory, array $data) - { - parent::__construct($nodeFactory, $data); - // Would be great, if we could inject the view here, but since the constructor is in the interface, we can't - // @todo: It's unfortunate we're using Typo3Fluid TemplateView directly here. We can't - // inject BackendViewFactory here since __construct() is polluted by NodeInterface. - // Remove __construct() from NodeInterface to have DI, then use BackendViewFactory here. - $view = GeneralUtility::makeInstance(TemplateView::class); - $templatePaths = $view->getRenderingContext()->getTemplatePaths(); - $templatePaths - ->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:ew_base/Resources/Private/Templates')]); - $templatePaths - ->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:ew_base/Resources/Private/Partials')]); - $this->templateView = $view; - } - - public function render(): array - { - $resultArray = $this->initializeResultArray(); - $parameterArray = $this->data['parameterArray']; - $config = $this->populateConfiguration($parameterArray['fieldConf']['config']); - $fieldId = StringUtility::getUniqueId('formengine-color-'); - - $file = $this->getFileObject($this->data['databaseRow'], $config['imageField']); - if (!$file) { - $languageService = $this->getLanguageService(); - $label = $languageService->sL( - 'LLL:EXT:ew_base/Resources/Private/Language/locallang_db.xlf:imageField.empty' - ); - $fieldLabel = $this->data['processedTca']['columns'][$config['imageField']]['label']; - $resultArray['html'] = ' -
-
-
- - ' . sprintf($label, '' . $fieldLabel . '') . ' - -
-
-
- '; - // Early return in case we do not find a file - return $resultArray; - } - - $fieldInformationResult = $this->renderFieldInformation(); - $fieldInformationHtml = $fieldInformationResult['html']; - $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false); - - $fieldControlResult = $this->renderFieldControl(); - $fieldControlHtml = $fieldControlResult['html']; - $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false); - - $fieldWizardResult = $this->renderFieldWizard(); - $fieldWizardHtml = $fieldWizardResult['html']; - $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false); - - $width = $this->formMaxWidth( - MathUtility::forceIntegerInRange( - $config['size'] ?? $this->defaultInputWidth, - $this->minimumInputWidth, - $this->maxInputWidth - ) - ); - - $arguments = [ - 'fieldInformation' => $fieldInformationHtml, - 'fieldControl' => $fieldControlHtml, - 'fieldWizard' => $fieldWizardHtml, - 'isAllowedFileExtension' => in_array( - strtolower($file->getExtension()), - GeneralUtility::trimExplode(',', strtolower($config['allowedExtensions'])), - true - ), - 'image' => $file, - 'formEngine' => [ - 'field' => [ - 'value' => $parameterArray['itemFormElValue'], - 'name' => $parameterArray['itemFormElName'], - ], - 'validation' => '[]', - ], - 'config' => $config, - 'width' => $width, - ]; - - if ($arguments['isAllowedFileExtension']) { - $resultArray['stylesheetFiles'][] = - 'EXT:ew_base/Resources/Public/JavaScript/form-engine/element/pick-color-from-image.css'; - $resultArray['javaScriptModules'][] = JavaScriptModuleInstruction::create( - '@evoweb/ew-base/form-engine/element/pick-color-from-image.js', - 'PickColorFromImage' - )->instance( - $fieldId, - $parameterArray['itemFormElValue'], - ($parameterArray['fieldConf']['config']['readOnly'] ?? false) - ); - $arguments['formEngine']['field']['id'] = $fieldId; - if ($config['required'] ?? false) { - $arguments['formEngine']['validation'] = $this->getValidationDataAsJsonString(['required' => true]); - } - } - - $this->templateView->assignMultiple($arguments); - $resultArray['html'] = $this->templateView->render('Form/ImageManipulationElement'); - - return $resultArray; - } - - protected function getFileObject(array $row, string $fieldName): ?File - { - $file = null; - $fileUid = !empty($row[$fieldName]) ? $row[$fieldName] : null; - if (is_array($fileUid) && isset($fileUid[0]['uid'])) { - $fileUid = $fileUid[0]['uid']; - } - if (MathUtility::canBeInterpretedAsInteger($fileUid)) { - try { - $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class); - $fileReference = $resourceFactory->getFileReferenceObject($fileUid); - $file = $fileReference->getOriginalFile(); - } catch (FileDoesNotExistException | \InvalidArgumentException) { - } - } - return $file; - } - - protected function populateConfiguration(array $baseConfiguration): array - { - $defaultConfig = self::$defaultConfig; - $config = array_replace_recursive($defaultConfig, $baseConfiguration); - $imageConfig = $this->data['processedTca']['columns'][$config['imageField']]; - $config['cropVariants'] = $imageConfig['config']['cropVariants'] ?? $defaultConfig['cropVariants']; - - if (!is_array($config['cropVariants'])) { - throw new InvalidConfigurationException('Crop variants configuration must be an array', 1485377267); - } - - $cropVariants = []; - foreach ($config['cropVariants'] as $id => $cropVariant) { - // Filter allowed aspect ratios - $cropVariant['allowedAspectRatios'] = array_filter( - $cropVariant['allowedAspectRatios'] ?? [], - static function ($aspectRatio) { - return !(bool)($aspectRatio['disabled'] ?? false); - } - ); - - // Ignore disabled crop variants - if (!empty($cropVariant['disabled'])) { - continue; - } - - if (empty($cropVariant['allowedAspectRatios'])) { - throw new InvalidConfigurationException( - 'Crop variants configuration ' . $id . ' contains no allowed aspect ratios', - 1620147893 - ); - } - - // Enforce a crop area (default is full image) - if (empty($cropVariant['cropArea'])) { - $cropVariant['cropArea'] = Area::createEmpty()->asArray(); - } - - $cropVariants[$id] = $cropVariant; - } - - $config['cropVariants'] = $cropVariants; - - $config['allowedExtensions'] ??= $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']; - - return $config; - } - - protected function processConfiguration(array $config, string &$elementValue, File $file): array - { - $cropVariantCollection = CropVariantCollection::create($elementValue, $config['cropVariants']); - if (empty($config['readOnly']) && !empty($file->getProperty('width'))) { - $cropVariantCollection = $cropVariantCollection->applyRatioRestrictionToSelectedCropArea($file); - $elementValue = (string)$cropVariantCollection; - } - $config['cropVariants'] = $cropVariantCollection->asArray(); - $config['allowedExtensions'] = implode( - ', ', - GeneralUtility::trimExplode(',', $config['allowedExtensions'], true) - ); - return $config; - } -} diff --git a/composer.json b/composer.json index 4aa554c..90c46be 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ } }, "require": { - "typo3/cms-core": "^12.4 || 12.4.x-dev || dev-main", + "typo3/cms-core": "^12.4 || 12.4.x-dev", "typo3/cms-backend": "*", "typo3/cms-extbase": "*", diff --git a/ext_localconf.php b/ext_localconf.php index 9b40451..5fd1db4 100755 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -3,7 +3,6 @@ defined('TYPO3') or die('access denied'); use Evoweb\EwBase\Form\Element\PickColorFromImage; -use Evoweb\EwBase\Form\Element\PickColorFromImagePre13; use Evoweb\EwBase\Form\FormDataProvider\UsercentricsDatabaseEditRow; use Evoweb\EwBase\Form\FormDataProvider\UsercentricsTcaInline; use Evoweb\EwBase\Hooks\UsercentricsPostRenderHook; @@ -22,11 +21,10 @@ call_user_func(function () { $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'][] = UsercentricsPostRenderHook::class . '->executePostRenderHook'; - $versionPre13 = (GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() < 13; $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1681197508] = [ 'nodeName' => 'pick-color-from-image', 'priority' => '70', - 'class' => $versionPre13 ? PickColorFromImagePre13::class : PickColorFromImage::class, + 'class' => PickColorFromImage::class, ]; $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][BaseSiteDatabaseEditRow::class] = [