diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index fb38b8a..3c4310e 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v3
- uses: tomasnorre/typo3-upload-ter@v2
with:
api-token: ${{ secrets.TYPO3_API_TOKEN }}
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 14f9fd0..dd2e2c2 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
-
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
-
name: Validate composer.json
@@ -16,7 +16,7 @@ jobs:
-
name: Cache composer dependencies
- uses: actions/cache@v1
+ uses: actions/cache@v3
with:
path: ~/.composer/cache
key: composer
@@ -34,25 +34,27 @@ jobs:
run: composer lint:editorconfig
- test:
+ test-unit:
runs-on: ubuntu-latest
strategy:
max-parallel: 2
matrix:
- php-versions: [7.4, 7.3]
- typo3-versions: [11, 10, 9]
+ php-versions: [8.2, 8.1, 8.0]
+ typo3-versions: [12, 11]
exclude:
- - php-versions: 7.3
- typo3-versions: 11
+ - php-versions: 8.0
+ typo3-versions: 12
include:
- - php-versions: 8
+ - php-versions: 7.4
typo3-versions: 11
+ - php-versions: 7.4
+ typo3-versions: 10
- name: PHP ${{ matrix.php-versions }} with TYPO3 ${{ matrix.typo3-versions }}
+ name: Unit Testing (PHP ${{ matrix.php-versions }}, TYPO3 ${{ matrix.typo3-versions }})
steps:
-
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
-
name: Setup PHP
@@ -63,7 +65,48 @@ jobs:
-
name: Cache composer dependencies
- uses: actions/cache@v1
+ uses: actions/cache@v3
+ with:
+ path: ~/.composer/cache
+ key: php-${{ matrix.php-versions }}-typo3-${{ matrix.typo3-versions }}
+
+ -
+ name: Install composer dependencies
+ run: composer require typo3/minimal "^${{ matrix.typo3-versions }}" --prefer-dist --no-progress --no-suggest
+
+ -
+ name: Unit Testing
+ run: composer test:unit
+
+
+ test-functional:
+ runs-on: ubuntu-latest
+
+ strategy:
+ max-parallel: 1
+ matrix:
+ php-versions: [8.2, 8.1]
+ typo3-versions: [12]
+
+ name: Functional Testing (PHP ${{ matrix.php-versions }}, TYPO3 ${{ matrix.typo3-versions }})
+ steps:
+ -
+ uses: actions/checkout@v3
+
+ -
+ name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ extensions: intl, mbstring, pdo_sqlite
+
+ -
+ name: Setup GraphicsMagick
+ run: sudo apt-get install -y graphicsmagick
+
+ -
+ name: Cache composer dependencies
+ uses: actions/cache@v3
with:
path: ~/.composer/cache
key: php-${{ matrix.php-versions }}-typo3-${{ matrix.typo3-versions }}
@@ -73,5 +116,5 @@ jobs:
run: composer require typo3/minimal "^${{ matrix.typo3-versions }}" --prefer-dist --no-progress --no-suggest
-
- name: Automated Testing
- run: composer test
+ name: Functional Testing
+ run: typo3DatabaseDriver=pdo_sqlite composer test:functional
diff --git a/Build/Testing/FunctionalTests.xml b/Build/Testing/FunctionalTests.xml
new file mode 100644
index 0000000..b6871ca
--- /dev/null
+++ b/Build/Testing/FunctionalTests.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ ../../Tests/Functional/
+
+
+
+
+
+
+
+
diff --git a/Build/Testing/FunctionalTestsBootstrap.php b/Build/Testing/FunctionalTestsBootstrap.php
new file mode 100644
index 0000000..443197d
--- /dev/null
+++ b/Build/Testing/FunctionalTestsBootstrap.php
@@ -0,0 +1,20 @@
+defineOriginalRootPath();
+ $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/tests');
+ $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/transient');
+});
diff --git a/Build/Testing/UnitTests.xml b/Build/Testing/UnitTests.xml
new file mode 100644
index 0000000..18f450f
--- /dev/null
+++ b/Build/Testing/UnitTests.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ ../../Tests/Unit/
+
+
+
+
+
+
+
+
diff --git a/Build/Testing/UnitTestsBootstrap.php b/Build/Testing/UnitTestsBootstrap.php
new file mode 100644
index 0000000..b3d535e
--- /dev/null
+++ b/Build/Testing/UnitTestsBootstrap.php
@@ -0,0 +1,75 @@
+getWebRoot(), '/'));
+ }
+ if (!getenv('TYPO3_PATH_WEB')) {
+ putenv('TYPO3_PATH_WEB=' . rtrim($testbase->getWebRoot(), '/'));
+ }
+
+ $testbase->defineSitePath();
+
+ $requestType = \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::REQUESTTYPE_BE | \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::REQUESTTYPE_CLI;
+ \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::run(0, $requestType);
+
+ $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3conf/ext');
+ $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3temp/assets');
+ $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3temp/var/tests');
+ $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3temp/var/transient');
+
+ // Retrieve an instance of class loader and inject to core bootstrap
+ $classLoader = require $testbase->getPackagesPath() . '/autoload.php';
+ \TYPO3\CMS\Core\Core\Bootstrap::initializeClassLoader($classLoader);
+
+ // Initialize default TYPO3_CONF_VARS
+ $configurationManager = new \TYPO3\CMS\Core\Configuration\ConfigurationManager();
+ $GLOBALS['TYPO3_CONF_VARS'] = $configurationManager->getDefaultConfiguration();
+
+ $cache = new \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend(
+ 'core',
+ new \TYPO3\CMS\Core\Cache\Backend\NullBackend('production', [])
+ );
+
+ // Set all packages to active
+ if (interface_exists(\TYPO3\CMS\Core\Package\Cache\PackageCacheInterface::class)) {
+ $packageManager = \TYPO3\CMS\Core\Core\Bootstrap::createPackageManager(
+ \TYPO3\CMS\Core\Package\UnitTestPackageManager::class,
+ \TYPO3\CMS\Core\Core\Bootstrap::createPackageCache($cache)
+ );
+ } else {
+ // v10 compatibility layer
+ $packageManager = \TYPO3\CMS\Core\Core\Bootstrap::createPackageManager(
+ \TYPO3\CMS\Core\Package\UnitTestPackageManager::class,
+ $cache
+ );
+ }
+
+ \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance(\TYPO3\CMS\Core\Package\PackageManager::class, $packageManager);
+ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::setPackageManager($packageManager);
+
+ $testbase->dumpClassLoadingInformation();
+
+ \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+});
diff --git a/Classes/Utility/ResponsiveImagesUtility.php b/Classes/Utility/ResponsiveImagesUtility.php
index 8a19fd7..d0757a2 100644
--- a/Classes/Utility/ResponsiveImagesUtility.php
+++ b/Classes/Utility/ResponsiveImagesUtility.php
@@ -1,5 +1,7 @@
imageService = $imageService;
+ }
+
+ public function injectResponsiveImagesUtility(ResponsiveImagesUtility $responsiveImagesUtility): void
{
$this->responsiveImagesUtility = $responsiveImagesUtility;
}
- /**
- * Initialize arguments.
- */
- public function initializeArguments()
+ public function initializeArguments(): void
{
parent::initializeArguments();
+ $this->registerUniversalTagAttributes();
+ // phpcs:disable Generic.Files.LineLength
+ $this->registerTagAttribute('alt', 'string', 'Specifies an alternate text for an image', false);
+ $this->registerTagAttribute('ismap', 'string', 'Specifies an image as a server-side image-map. Rarely used. Look at usemap instead', false);
+ $this->registerTagAttribute('longdesc', 'string', 'Specifies the URL to a document that contains a long description of an image', false);
+ $this->registerTagAttribute('usemap', 'string', 'Specifies an image as a client-side image-map', false);
+ $this->registerTagAttribute('loading', 'string', 'Native lazy-loading for images property. Can be "lazy", "eager" or "auto"', false);
+ $this->registerTagAttribute('decoding', 'string', 'Provides an image decoding hint to the browser. Can be "sync", "async" or "auto"', false);
+
+ $this->registerArgument('src', 'string', 'a path to a file, a combined FAL identifier or an uid (int). If $treatIdAsReference is set, the integer is considered the uid of the sys_file_reference record. If you already got a FAL object, consider using the $image parameter instead', false, '');
+ $this->registerArgument('treatIdAsReference', 'bool', 'given src argument is a sys_file_reference record', false, false);
+ $this->registerArgument('image', 'object', 'a FAL object (\\TYPO3\\CMS\\Core\\Resource\\File or \\TYPO3\\CMS\\Core\\Resource\\FileReference)');
+ $this->registerArgument('crop', 'string|bool', 'overrule cropping of image (setting to FALSE disables the cropping set in FileReference)');
+ $this->registerArgument('cropVariant', 'string', 'select a cropping variant, in case multiple croppings have been specified or stored in FileReference', false, 'default');
+ $this->registerArgument('fileExtension', 'string', 'Custom file extension to use');
+
+ $this->registerArgument('width', 'string', 'width of the image. This can be a numeric value representing the fixed width of the image in pixels. But you can also perform simple calculations by adding "m" or "c" to the value. See imgResource.width for possible options.');
+ $this->registerArgument('height', 'string', 'height of the image. This can be a numeric value representing the fixed height of the image in pixels. But you can also perform simple calculations by adding "m" or "c" to the value. See imgResource.width for possible options.');
+ $this->registerArgument('minWidth', 'int', 'minimum width of the image');
+ $this->registerArgument('minHeight', 'int', 'minimum height of the image');
+ $this->registerArgument('maxWidth', 'int', 'maximum width of the image');
+ $this->registerArgument('maxHeight', 'int', 'maximum height of the image');
+ $this->registerArgument('absolute', 'bool', 'Force absolute URL', false, false);
+ // phpcs:enable
+
$this->registerArgument('srcset', 'mixed', 'Image sizes that should be rendered.', false);
$this->registerArgument(
'sizes',
@@ -60,20 +87,6 @@ public function initializeArguments()
false,
'svg, gif'
);
-
- if (version_compare(TYPO3_version, '10.3', '<')) {
- $this->registerArgument(
- 'fileExtension',
- 'string',
- 'Custom file extension to use for images'
- );
-
- $this->registerArgument(
- 'loading',
- 'string',
- 'Native lazy-loading for images property. Can be "lazy", "eager" or "auto". Used on image files only.'
- );
- }
}
/**
@@ -84,7 +97,7 @@ public function initializeArguments()
* @throws \TYPO3Fluid\Fluid\Core\Exception
* @return string Rendered tag
*/
- public function render()
+ public function render(): string
{
$src = (string)$this->arguments['src'];
if (($src === '' && is_null($this->arguments['image']))
@@ -104,12 +117,6 @@ public function render()
), 1631539412); // Original code: 1618989190
}
- // Fall back to TYPO3 default if no responsive image feature was selected
- // This also covers external image urls
- if (!$this->arguments['breakpoints'] && !$this->arguments['srcset']) {
- return parent::render();
- }
-
// Add loading attribute to tag
if (in_array($this->arguments['loading'] ?? '', ['lazy', 'eager', 'auto'], true)) {
$this->tag->addAttribute('loading', $this->arguments['loading']);
@@ -120,7 +127,7 @@ public function render()
$image = $this->imageService->getImage(
$src,
$this->arguments['image'],
- $this->arguments['treatIdAsReference']
+ (bool) $this->arguments['treatIdAsReference']
);
// Determine cropping settings
@@ -132,7 +139,11 @@ public function render()
$cropVariant = $this->arguments['cropVariant'] ?: 'default';
$cropArea = $cropVariantCollection->getCropArea($cropVariant);
- $focusArea = $cropVariantCollection->getFocusArea($cropVariant);
+
+ $focusArea = null;
+ if (!$this->tag->hasAttribute('data-focus-area')) {
+ $focusArea = $cropVariantCollection->getFocusArea($cropVariant);
+ }
// Generate fallback image
$processingInstructions = [
@@ -149,10 +160,10 @@ public function render()
if (!is_null($this->arguments['maxWidth'])) {
$processingInstructions['maxWidth'] = $this->arguments['maxWidth'];
}
- $fallbackImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
if ($this->arguments['breakpoints']) {
// Generate picture tag
+ $fallbackImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
$this->tag = $this->responsiveImagesUtility->createPictureTag(
$image,
$fallbackImage,
@@ -164,12 +175,13 @@ public function render()
$this->arguments['absolute'],
$this->arguments['lazyload'],
$this->arguments['ignoreFileExtensions'],
- $this->arguments['placeholderSize'],
+ (int) $this->arguments['placeholderSize'],
$this->arguments['placeholderInline'],
$this->arguments['fileExtension']
);
- } else {
+ } elseif ($this->arguments['srcset']) {
// Generate img tag with srcset
+ $fallbackImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
$this->tag = $this->responsiveImagesUtility->createImageTagWithSrcset(
$image,
$fallbackImage,
@@ -181,19 +193,44 @@ public function render()
$this->arguments['absolute'],
$this->arguments['lazyload'],
$this->arguments['ignoreFileExtensions'],
- $this->arguments['placeholderSize'],
+ (int) $this->arguments['placeholderSize'],
+ $this->arguments['placeholderInline'],
+ $this->arguments['fileExtension']
+ );
+ } else {
+ // For simple images, height calculation is not a problem and is done the same way
+ // the core does it
+ $processingInstructions = array_merge($processingInstructions, [
+ 'height' => $this->arguments['height'],
+ 'minHeight' => $this->arguments['minHeight'],
+ 'maxHeight' => $this->arguments['maxHeight']
+ ]);
+ $fallbackImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
+
+ $this->tag = $this->responsiveImagesUtility->createSimpleImageTag(
+ $fallbackImage,
+ null,
+ $this->tag,
+ $focusArea,
+ $this->arguments['absolute'],
+ $this->arguments['lazyload'],
+ (int) $this->arguments['placeholderSize'],
$this->arguments['placeholderInline'],
$this->arguments['fileExtension']
);
}
} catch (ResourceDoesNotExistException $e) {
// thrown if file does not exist
+ throw new Exception($e->getMessage(), 1678270145, $e); // Original code: 1509741911
} catch (\UnexpectedValueException $e) {
// thrown if a file has been replaced with a folder
+ throw new Exception($e->getMessage(), 1678270146, $e); // Original code: 1509741912
} catch (\RuntimeException $e) {
// RuntimeException thrown if a file is outside of a storage
+ throw new Exception($e->getMessage(), 1678270147, $e); // Original code: 1509741913
} catch (\InvalidArgumentException $e) {
// thrown if file storage does not exist
+ throw new Exception($e->getMessage(), 1678270148, $e); // Original code: 1509741914
}
return $this->tag->render();
diff --git a/Classes/ViewHelpers/MediaViewHelper.php b/Classes/ViewHelpers/MediaViewHelper.php
index 98e4b61..e19a527 100644
--- a/Classes/ViewHelpers/MediaViewHelper.php
+++ b/Classes/ViewHelpers/MediaViewHelper.php
@@ -1,33 +1,52 @@
imageService = $imageService;
+ }
+
+ public function injectResponsiveImagesUtility(ResponsiveImagesUtility $responsiveImagesUtility): void
{
$this->responsiveImagesUtility = $responsiveImagesUtility;
}
- /**
- * Initialize arguments.
- */
- public function initializeArguments()
+
+ public function initializeArguments(): void
{
parent::initializeArguments();
+ $this->registerUniversalTagAttributes();
+ // phpcs:disable Generic.Files.LineLength
+ $this->registerTagAttribute('alt', 'string', 'Specifies an alternate text for an image', false);
+ $this->registerArgument('file', 'object', 'File', true);
+ $this->registerArgument('additionalConfig', 'array', 'This array can hold additional configuration that is passed though to the Renderer object', false, []);
+ $this->registerArgument('width', 'string', 'This can be a numeric value representing the fixed width of in pixels. But you can also perform simple calculations by adding "m" or "c" to the value. See imgResource.width for possible options.');
+ $this->registerArgument('height', 'string', 'This can be a numeric value representing the fixed height in pixels. But you can also perform simple calculations by adding "m" or "c" to the value. See imgResource.width for possible options.');
+ $this->registerArgument('cropVariant', 'string', 'select a cropping variant, in case multiple croppings have been specified or stored in FileReference', false, 'default');
+ $this->registerArgument('fileExtension', 'string', 'Custom file extension to use for images');
+ $this->registerArgument('loading', 'string', 'Native lazy-loading for images property. Can be "lazy", "eager" or "auto". Used on image files only.');
+ $this->registerArgument('decoding', 'string', 'Provides an image decoding hint to the browser. Can be "sync", "async" or "auto"', false);
+ // phpcs:enable
+
$this->registerArgument('srcset', 'mixed', 'Image sizes that should be rendered.', false);
$this->registerArgument(
'sizes',
@@ -59,40 +78,110 @@ public function initializeArguments()
false,
'svg, gif'
);
+ }
- if (version_compare(TYPO3_version, '10.3', '<')) {
- $this->registerArgument(
- 'fileExtension',
- 'string',
- 'Custom file extension to use for images'
- );
+ /**
+ * Render a given media file.
+ *
+ * @throws \UnexpectedValueException
+ * @throws Exception
+ */
+ public function render(): string
+ {
+ $file = $this->arguments['file'];
+ $additionalConfig = (array)$this->arguments['additionalConfig'];
+ $width = $this->arguments['width'];
+ $height = $this->arguments['height'];
+
+ // get Resource Object (non ExtBase version)
+ if (is_callable([$file, 'getOriginalResource'])) {
+ // We have a domain model, so we need to fetch the FAL resource object from there
+ $file = $file->getOriginalResource();
+ }
- $this->registerArgument(
- 'loading',
- 'string',
- 'Native lazy-loading for images property. Can be "lazy", "eager" or "auto". Used on image files only.'
+ if (!$file instanceof FileInterface) {
+ throw new \UnexpectedValueException(
+ 'Supplied file object type ' . get_class($file) . ' must be FileInterface.',
+ 1678270961 // Original code: 1454252193
);
}
+
+ if (!$this->isKnownFileExtension($this->arguments['fileExtension'])) {
+ throw new Exception(sprintf(
+ 'The extension %s is not specified in %s as a valid image file extension and can not be processed.',
+ $this->arguments['fileExtension'],
+ '$GLOBALS[\'TYPO3_CONF_VARS\'][\'GFX\'][\'imagefile_ext\']'
+ ), 1631539412); // Original code: 1619030957
+ }
+
+ $fileRenderer = GeneralUtility::makeInstance(RendererRegistry::class)->getRenderer($file);
+
+ // Fallback to image when no renderer is found
+ if ($fileRenderer === null) {
+ if ($this->arguments['breakpoints']) {
+ return $this->renderPicture($file, $width, $height, $this->arguments['fileExtension'] ?? null);
+ } elseif ($this->arguments['srcset']) {
+ return $this->renderImageSrcset($file, $width, $height, $this->arguments['fileExtension'] ?? null);
+ } else {
+ return $this->renderSimpleImage($file, $width, $height, $this->arguments['fileExtension'] ?? null);
+ }
+ }
+ $additionalConfig = array_merge_recursive($this->arguments, $additionalConfig);
+ return $fileRenderer->render($file, $width, $height, $additionalConfig);
}
/**
- * Render img tag
+ * Render simple img tag
*
- * @param FileInterface $image
- * @param string $width
- * @param string $height
- * @param string|null $fileExtension
- * @return string Rendered img tag
+ * @param string $width
+ * @param string $height
+ * @return string Rendered img tag
*/
- protected function renderImage(FileInterface $image, $width, $height, ?string $fileExtension = null)
+ protected function renderSimpleImage(FileInterface $image, $width, $height, ?string $fileExtension): string
{
- if ($this->arguments['breakpoints']) {
- return $this->renderPicture($image, $width, $height, $fileExtension);
- } elseif ($this->arguments['srcset']) {
- return $this->renderImageSrcset($image, $width, $height, $fileExtension);
- } else {
- return parent::renderImage($image, $width, $height, $fileExtension);
+ $cropVariant = $this->arguments['cropVariant'] ?: 'default';
+ $cropString = $image instanceof FileReference ? $image->getProperty('crop') : '';
+ $cropVariantCollection = CropVariantCollection::create((string)$cropString);
+ $cropArea = $cropVariantCollection->getCropArea($cropVariant);
+ $processingInstructions = [
+ 'width' => $width,
+ 'height' => $height,
+ 'crop' => $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image),
+ ];
+ if (!empty($fileExtension)) {
+ $processingInstructions['fileExtension'] = $fileExtension;
+ }
+ $processedImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
+ $imageUri = $this->imageService->getImageUri($processedImage);
+
+ if (!$this->tag->hasAttribute('data-focus-area')) {
+ $focusArea = $cropVariantCollection->getFocusArea($cropVariant);
+ if (!$focusArea->isEmpty()) {
+ $this->tag->addAttribute('data-focus-area', $focusArea->makeAbsoluteBasedOnFile($image));
+ }
+ }
+ $this->tag->addAttribute('src', $imageUri);
+ $this->tag->addAttribute('width', $processedImage->getProperty('width'));
+ $this->tag->addAttribute('height', $processedImage->getProperty('height'));
+ if (in_array($this->arguments['loading'] ?? '', ['lazy', 'eager', 'auto'], true)) {
+ $this->tag->addAttribute('loading', $this->arguments['loading']);
}
+ if (in_array($this->arguments['decoding'] ?? '', ['sync', 'async', 'auto'], true)) {
+ $this->tag->addAttribute('decoding', $this->arguments['decoding']);
+ }
+
+ $alt = $image->getProperty('alternative');
+ $title = $image->getProperty('title');
+
+ // The alt-attribute is mandatory to have valid html-code, therefore add it even if it is empty
+ if (empty($this->arguments['alt'])) {
+ $this->tag->addAttribute('alt', $alt);
+ }
+ if (empty($this->arguments['title']) && $title) {
+ $this->tag->addAttribute('title', $title);
+ }
+
+ return $this->tag->render();
}
/**
@@ -137,7 +226,7 @@ protected function renderPicture(FileInterface $image, $width, $height, ?string
false,
$this->arguments['lazyload'],
$this->arguments['ignoreFileExtensions'],
- $this->arguments['placeholderSize'],
+ (int) $this->arguments['placeholderSize'],
$this->arguments['placeholderInline'],
$fileExtension
);
@@ -171,6 +260,9 @@ protected function renderImageSrcset(FileInterface $image, $width, $height, ?str
if (in_array($this->arguments['loading'] ?? '', ['lazy', 'eager', 'auto'], true)) {
$this->tag->addAttribute('loading', $this->arguments['loading']);
}
+ if (in_array($this->arguments['decoding'] ?? '', ['sync', 'async', 'auto'], true)) {
+ $this->tag->addAttribute('decoding', $this->arguments['decoding']);
+ }
// Generate image tag
$this->tag = $this->responsiveImagesUtility->createImageTagWithSrcset(
@@ -184,7 +276,7 @@ protected function renderImageSrcset(FileInterface $image, $width, $height, ?str
false,
$this->arguments['lazyload'],
$this->arguments['ignoreFileExtensions'],
- $this->arguments['placeholderSize'],
+ (int) $this->arguments['placeholderSize'],
$this->arguments['placeholderInline'],
$fileExtension
);
@@ -214,9 +306,19 @@ protected function generateFallbackImage(
if (!empty($fileExtension)) {
$processingInstructions['fileExtension'] = $fileExtension;
}
- $imageService = $this->getImageService();
- $fallbackImage = $imageService->applyProcessingInstructions($image, $processingInstructions);
+ $fallbackImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
return $fallbackImage;
}
+
+ protected function isKnownFileExtension($fileExtension): bool
+ {
+ $fileExtension = (string) $fileExtension;
+ // Skip if no file extension was specified
+ if ($fileExtension === '') {
+ return true;
+ }
+ // Check against list of supported extensions
+ return GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExtension);
+ }
}
diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml
new file mode 100644
index 0000000..d9c37c6
--- /dev/null
+++ b/Configuration/Services.yaml
@@ -0,0 +1,8 @@
+services:
+ _defaults:
+ autowire: true
+ autoconfigure: true
+ public: false
+
+ Sitegeist\ResponsiveImages\:
+ resource: '../Classes/*'
diff --git a/Configuration/TypoScript/Base/constants.ts b/Configuration/TypoScript/Base/constants.ts
deleted file mode 100644
index b634033..0000000
--- a/Configuration/TypoScript/Base/constants.ts
+++ /dev/null
@@ -1 +0,0 @@
-@import 'EXT:sms_responsive_images/Configuration/TypoScript/Base/constants.typoscript'
diff --git a/Configuration/TypoScript/Base/setup.ts b/Configuration/TypoScript/Base/setup.ts
deleted file mode 100644
index 1337be2..0000000
--- a/Configuration/TypoScript/Base/setup.ts
+++ /dev/null
@@ -1 +0,0 @@
-@import 'EXT:sms_responsive_images/Configuration/TypoScript/Base/setup.typoscript'
diff --git a/Documentation/Index.rst b/Documentation/Index.rst
index d432015..897be99 100644
--- a/Documentation/Index.rst
+++ b/Documentation/Index.rst
@@ -30,7 +30,7 @@ SMS Responsive Images
TYPO3 CMS,responsive images,srcset,sizes,picture,highdpi,retina,image,aspect ratio,cropping,lazyload,placeholder
:Copyright:
- 2017
+ 2023
:Author:
Simon Praetorius
diff --git a/Documentation/Links.rst b/Documentation/Links.rst
index 9710653..3402d53 100644
--- a/Documentation/Links.rst
+++ b/Documentation/Links.rst
@@ -19,6 +19,3 @@ Links
:Git Repository:
https://github.com/sitegeist/sms-responsive-images
-
-:Contact:
- `@s2bproject `__, `@sitegeist_de `__
diff --git a/Documentation/Settings.cfg b/Documentation/Settings.cfg
index fca34a5..6fb2be8 100644
--- a/Documentation/Settings.cfg
+++ b/Documentation/Settings.cfg
@@ -25,13 +25,13 @@ project = SMS Responsive Images
# ... (recommended) version, displayed next to title (desktop) and in