Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Add prefix data-* tosrc and srcset #72

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Classes/Domain/Model/PictureConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class PictureConfiguration
protected array $breakpoints = [];
protected array $sources = [];
protected bool $addSources = false;
protected bool $addSrcPrefix = false;
protected bool $addLazyLoading = false;
protected string $lazyLoading = '';
protected array $arguments;
Expand All @@ -35,6 +36,7 @@ public function __construct(array $arguments, array $typoScriptSettings, FileInt
{
$this->arguments = $arguments;
$fileExtension = $arguments['fileExtension'] ?? $image->getExtension();
$this->addSrcPrefix = $arguments['srcPrefix'] ?? false;
if ($image->getExtension() !== 'svg') {
$this->addWebp = (bool)($fileExtension === 'webp' ? false : ($arguments['addWebp'] ?? $typoScriptSettings['addWebp'] ?? false));
$this->onlyWebp = (bool)($fileExtension === 'webp' ? false : ($arguments['onlyWebp'] ?? $typoScriptSettings['onlyWebp'] ?? false));
Expand Down Expand Up @@ -98,6 +100,11 @@ public function getSourceConfiguration(): array
return $configuration;
}

public function srcPrefixShouldBeAdded(): bool
{
return $this->addSrcPrefix;
}

public function lazyLoadingShouldBeAdded(): bool
{
return $this->addLazyLoading;
Expand Down
30 changes: 22 additions & 8 deletions Classes/ViewHelpers/ImageViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ public function initializeArguments(): void
'array',
'Array for rendering of multiple images.'
);

$this->registerArgument(
'srcPrefix',
'bool',
'If true then adds data-* prefix to all src and srcset'
);

}

/**
Expand Down Expand Up @@ -261,6 +268,7 @@ protected function buildSingleTag(string $tagName, array $configuration, FileInt
// set the default processed image (we might need the width and height of this image later on) and generate a single image uri as the src fallback
$processedImage = $this->applyProcessingInstructions($processingInstructions, $image);
$imageUri = $this->imageService->getImageUri($processedImage, $this->arguments['absolute']);
$srcPrefix = $this->getSrcPrefix();

switch ($tagName) {
case 'img':
Expand All @@ -273,9 +281,9 @@ protected function buildSingleTag(string $tagName, array $configuration, FileInt
}
}
if ($srcsetValue !== '') {
$tag->addAttribute('srcset', $srcsetValue);
$tag->addAttribute($srcPrefix . 'srcset', $srcsetValue);
}
$tag->addAttribute('src', $imageUri);
$tag->addAttribute($srcPrefix . 'src', $imageUri);
if (!empty($configuration['sizes'])) {
$tag->addAttribute('sizes', $configuration['sizes']);
}
Expand Down Expand Up @@ -303,9 +311,9 @@ protected function buildSingleTag(string $tagName, array $configuration, FileInt

// Add content of src attribute to srcset attribute as the source element has no src attribute.
if ($srcsetValue !== '') {
$tag->addAttribute('srcset', $srcsetValue);
$tag->addAttribute($srcPrefix . 'srcset', $srcsetValue);
} else {
$tag->addAttribute('srcset', $imageUri);
$tag->addAttribute($srcPrefix . 'srcset', $imageUri);
}

// Add attributes.
Expand Down Expand Up @@ -373,12 +381,13 @@ protected function addRetina(array $processingInstructions, TagBuilder $tag, Fil
// Process regular image.
$processedImageRegular = $this->applyProcessingInstructions($processingInstructions, $image);
$imageUriRegular = $this->imageService->getImageUri($processedImageRegular, $this->arguments['absolute']);
$srcPrefix = $this->getSrcPrefix();

// Process additional retina images. Tag value can be gathered for source tags from srcset value as there it
// was to be set already because adding retina is not mandatory.
if ($tag->hasAttribute('srcset')) {
$tagValue = htmlspecialchars_decode($tag->getAttribute('srcset') ?? '');
$tag->removeAttribute('srcset');
if ($tag->hasAttribute($srcPrefix . 'srcset')) {
$tagValue = htmlspecialchars_decode($tag->getAttribute($srcPrefix . 'srcset') ?? '');
$tag->removeAttribute($srcPrefix . 'srcset');
} else {
$tagValue = $imageUriRegular;
}
Expand All @@ -405,7 +414,7 @@ protected function addRetina(array $processingInstructions, TagBuilder $tag, Fil
$tagValue .= ', ' . $imageUriRetina . ' ' . $retinaString;
}

$tag->addAttribute('srcset', $tagValue);
$tag->addAttribute($srcPrefix . 'srcset', $tagValue);
}

/**
Expand Down Expand Up @@ -536,4 +545,9 @@ protected function applyProcessingInstructions(array $processingInstructions, Fi

return $this->imageService->applyProcessingInstructions($image, $processingInstructions);
}

public function getSrcPrefix(): string
{
return $this->pictureConfiguration->srcPrefixShouldBeAdded() ? 'data-' : '';
}
}
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,16 @@ Use a proper configured Fluid template adding the namespace when using this View

See `EXT:picture/Configuration/TypoScript/setup.typoscript` for possible configuration options (key: `plugin.tx_picture`):

| TypoScript Configuration option | Description |
|---------------------------------|-------------|
| addWebp | Add webp alternative image files as sources. <br>_default: 0_ |
| onlyWebp | Enable only images in webp format and for all size variants. <br>_default: 0_ |
| useRetina | Add retina (2x) version of all images as sizes variants. <br>_default: 0_ |
| lossless | Enable lossless compression for webp images. <br>_default: 0_ |
| retina | Use custom or multiple multipliers for calculating retina image variants. <br>_default: <br>retina.2 = 2x<br>Only works in combination with `useRetina = 1` |
| breakpoints | Use named breakpoints for easier markup of different image sizes for one picture element.<br>_default: empty_. |
| lazyLoading | Use the `loading` attribute with images. See [Browser Native Lazy Loading by Default](https://b13.com/blog/lazy-loading-just-got-lazier-in-typo3-v10)<br>_default: {$types.content.image.lazyLoading}_ |
| TypoScript Configuration option | Description |
|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| addWebp | Add webp alternative image files as sources. <br>_default: 0_ |
| onlyWebp | Enable only images in webp format and for all size variants. <br>_default: 0_ |
| srcPrefix | Enable data-* prefix to all src and srcset. <br>_default: 0_ |
| useRetina | Add retina (2x) version of all images as sizes variants. <br>_default: 0_ |
| lossless | Enable lossless compression for webp images. <br>_default: 0_ |
| retina | Use custom or multiple multipliers for calculating retina image variants. <br>_default: <br>retina.2 = 2x<br>Only works in combination with `useRetina = 1` |
| breakpoints | Use named breakpoints for easier markup of different image sizes for one picture element.<br>_default: empty_. |
| lazyLoading | Use the `loading` attribute with images. See [Browser Native Lazy Loading by Default](https://b13.com/blog/lazy-loading-just-got-lazier-in-typo3-v10)<br>_default: {$types.content.image.lazyLoading}_ |

## Attributes

Expand All @@ -67,6 +68,10 @@ This attribute is ignored if `onlyWebp` option is active.
Enable only images in webp format and for all size variants.
Enabling this option disables `addWebp` setting.

### srcPrefix
Enable `data-*` prefix to all `src` and `srcset` allowing to use all king do JS lazy load images libraries. Can be used
in cases when standard `loading="lazy"` is not enough.

### lossless
Enable lossless compression for webp images. If you find your webp images lacking in quality compared to jpg/png images, enable
this option to overwrite default settings for ImageMagick/GraphicsMagick.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html
xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:i="http://typo3.org/ns/B13/Picture/ViewHelpers"
data-namespace-typo3-fluid="true"
>
<f:spaceless>
<i:image src="EXT:picture/Resources/Public/Test/Picture.png" width="400" useRetina="1" addWebp="1" srcPrefix="1" alt="Testimage 400px width with retina and addWebp and srcPrefix" />
</f:spaceless>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html
xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:i="http://typo3.org/ns/B13/Picture/ViewHelpers"
data-namespace-typo3-fluid="true"
>
<f:spaceless>
<i:image src="EXT:picture/Resources/Public/Test/Picture.png" width="400" srcPrefix="1" alt="Testimage 400px width and srcPrefix" />
</f:spaceless>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"pages"
,"uid","pid","title","slug"
,1,0,"root","/"
"sys_template"
,"uid","pid","root","constants","config"
,1,1,1,styles.content.image.lazyLoading=lazy,"@import 'EXT:picture/Configuration/TypoScript/test.typoscript'
page = PAGE
page.config.disableAllHeaderCode = 1
page.10 = FLUIDTEMPLATE
page.10.templateRootPaths.10 = EXT:picture/Tests/Functional/Frontend/Fixtures/Templates
page.10.templateName = SimpleImageWithRetinaAndWebpAndSrcPrefixOption.html
config.absRefPrefix = /
"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"pages"
,"uid","pid","title","slug"
,1,0,"root","/"
"sys_template"
,"uid","pid","root","constants","config"
,1,1,1,styles.content.image.lazyLoading=lazy,"@import 'EXT:picture/Configuration/TypoScript/test.typoscript'
page = PAGE
page.config.disableAllHeaderCode = 1
page.10 = FLUIDTEMPLATE
page.10.templateRootPaths.10 = EXT:picture/Tests/Functional/Frontend/Fixtures/Templates
page.10.templateName = SimpleImageWithSrcPrefix.html
config.absRefPrefix = /
"
28 changes: 28 additions & 0 deletions Tests/Functional/Frontend/TagRenderingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ public function simpleImageWithOnlyWebp(): void
self::assertStringContainsString($this->anonymouseProcessdImage($expected), $this->anonymouseProcessdImage($body));
}

/**
* @test
*/
public function simpleImageWithRetinaAndWebpAndSrcPrefixOption(): void
{
$this->importCSVDataSet(__DIR__ . '/Fixtures/simple_image_with_retina_and_webp_and_src_prefix_option.csv');
$response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
$body = (string)$response->getBody();
$expected = '<picture>
<source type="image/webp" data-srcset="/typo3temp/assets/_processed_/a/2/csm_Picture_cfb567934c.webp, /typo3temp/assets/_processed_/a/2/csm_Picture_089357224d.webp 2x, /typo3temp/assets/_processed_/a/2/csm_Picture_d356d2dde1.webp 3x" />
<img alt="Testimage 400px width with retina and addWebp and srcPrefix" data-src="/typo3temp/assets/_processed_/a/2/csm_Picture_23f7889ff5.png" width="400" height="200" loading="lazy" data-srcset="/typo3temp/assets/_processed_/a/2/csm_Picture_23f7889ff5.png, /typo3temp/assets/_processed_/a/2/csm_Picture_13dd378eeb.png 2x, /typo3temp/assets/_processed_/a/2/csm_Picture_3c8b5cfedf.png 3x" />
</picture>';
$expected = implode('', GeneralUtility::trimExplode("\n", $expected));
self::assertStringContainsString($this->anonymouseProcessdImage($expected), $this->anonymouseProcessdImage($body));
}

/**
* @test
*/
Expand All @@ -77,6 +93,18 @@ public function simpleImageWithRetinaOption(): void
self::assertStringContainsString($this->anonymouseProcessdImage($expected), $this->anonymouseProcessdImage($body));
}

/**
* @test
*/
public function simpleImageWithSrcPrefix(): void
{
$this->importCSVDataSet(__DIR__ . '/Fixtures/simple_image_with_src_prefix.csv');
$response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
$body = (string)$response->getBody();
$expected = '<img alt="Testimage 400px width and srcPrefix" data-src="/typo3temp/assets/_processed_/a/2/csm_Picture_23f7889ff5.png" width="400" height="200" loading="lazy" />';
self::assertStringContainsString($this->anonymouseProcessdImage($expected), $this->anonymouseProcessdImage($body));
}

/**
* @test
*/
Expand Down