Browse Source

Issue #3373333 by paulsheldrake, Chi: New filter to base64 encode and image

merge-requests/20/merge
Chi 11 months ago
parent
commit
ed7ae10bc6
  1. 9
      docs/cheat-sheet.md
  2. 14
      src/TwigTweakExtension.php
  3. 8
      tests/src/Functional/TwigTweakTest.php
  4. 8
      tests/twig_tweak_test/templates/twig-tweak-test.html.twig
  5. 2
      twig_tweak.api.php

9
docs/cheat-sheet.md

@ -285,6 +285,15 @@ This is an opposite of core `without` filter and adds properties instead of remo
{{ content|with(['field_image', '#title'], 'Photo'|t) }} {{ content|with(['field_image', '#title'], 'Photo'|t) }}
``` ```
## Data URI
The filter generates a URL using the data scheme as defined in [RFC 2397](https://datatracker.ietf.org/doc/html/rfc2397)
```twig
{# Inline image. #}
<img src="{{ '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100" height="50" fill="lime"/></svg>'|data_uri('image/svg+xml') }}" alt="{{ 'Rectangle'|t }}"/>
{# Image from file system. #}
<img src="{{ source(directory ~ '/images/logo.svg')|data_uri('image/svg+xml') }}" alt="{{ 'Logo'|t }}"/>
```
## Children ## Children
```twig ```twig
<ul> <ul>

14
src/TwigTweakExtension.php

@ -110,6 +110,7 @@ class TwigTweakExtension extends AbstractExtension {
new TwigFilter('truncate', [Unicode::class, 'truncate']), new TwigFilter('truncate', [Unicode::class, 'truncate']),
new TwigFilter('view', [self::class, 'viewFilter']), new TwigFilter('view', [self::class, 'viewFilter']),
new TwigFilter('with', [self::class, 'withFilter']), new TwigFilter('with', [self::class, 'withFilter']),
new TwigFilter('data_uri', [self::class, 'dataUriFilter']),
new TwigFilter('children', [self::class, 'childrenFilter']), new TwigFilter('children', [self::class, 'childrenFilter']),
new TwigFilter('file_uri', [self::class, 'fileUriFilter']), new TwigFilter('file_uri', [self::class, 'fileUriFilter']),
new TwigFilter('file_url', [self::class, 'fileUrlFilter']), new TwigFilter('file_url', [self::class, 'fileUrlFilter']),
@ -570,6 +571,19 @@ class TwigTweakExtension extends AbstractExtension {
return $build; return $build;
} }
/**
* Creates a data URI (RFC 2397).
*/
public static function dataUriFilter(string $data, string $mime, array $parameters = []): string {
$uri = 'data:' . $mime;
foreach ($parameters as $key => $value) {
$uri .= ';' . $key . '=' . rawurlencode($value);
}
$uri .= \str_starts_with($data, 'text/') ?
',' . rawurlencode($data) : ';base64,' . base64_encode($data);
return $uri;
}
/** /**
* Adds new element to the array. * Adds new element to the array.
* *

8
tests/src/Functional/TwigTweakTest.php

@ -342,6 +342,14 @@ final class TwigTweakTest extends BrowserTestBase {
$xpath = '//div[@class = "tt-with-nested" and text() = "{alpha:{beta:{gamma:456}}}"]'; $xpath = '//div[@class = "tt-with-nested" and text() = "{alpha:{beta:{gamma:456}}}"]';
$this->assertXpath($xpath); $this->assertXpath($xpath);
// -- Data URI (SVG).
$xpath = '//div[@class = "tt-data-uri-svg"]/img[@src = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMDAiIGhlaWdodD0iNTAiIGZpbGw9ImxpbWUiLz48L3N2Zz4="]';
$this->assertXpath($xpath);
// -- Data URI (Iframe).
$xpath = '//div[@class = "tt-data-uri-iframe"]/iframe[@src = "data:text/html;charset=UTF-8;base64,PGgxPkhlbGxvIHdvcmxkITwvaDE+"]';
$this->assertXpath($xpath);
// -- 'children'. // -- 'children'.
$xpath = '//div[@class = "tt-children" and text() = "doremi"]'; $xpath = '//div[@class = "tt-children" and text() = "doremi"]';
$this->assertXpath($xpath); $this->assertXpath($xpath);

8
tests/twig_tweak_test/templates/twig-tweak-test.html.twig

@ -67,10 +67,16 @@
<div class="tt-image-style">{{ 'public://images/ocean.jpg'|image_style('thumbnail') }}</div> <div class="tt-image-style">{{ 'public://images/ocean.jpg'|image_style('thumbnail') }}</div>
<div class="tt-transliterate">{{ 'Привет!'|transliterate('ru') }}</div> <div class="tt-transliterate">{{ 'Привет!'|transliterate('ru') }}</div>
<div class="tt-check-markup">{{ '<b>bold</b> <strong>strong</strong>'|check_markup('twig_tweak_test') }}</div> <div class="tt-check-markup">{{ '<b>bold</b> <strong>strong</strong>'|check_markup('twig_tweak_test') }}</div>
<div class="tt-format-size">{{ 12345|format_size() }}</div> <div class="tt-format-size">{{ 12345|format_size }}</div>
<div class="tt-truncate">{{ 'Hello world!'|truncate(10, true, true) }}</div> <div class="tt-truncate">{{ 'Hello world!'|truncate(10, true, true) }}</div>
<div class="tt-with">{{ {'#markup':'Example'}|with('#prefix', '<b>')|with('#suffix', '</b>') }}</div> <div class="tt-with">{{ {'#markup':'Example'}|with('#prefix', '<b>')|with('#suffix', '</b>') }}</div>
<div class="tt-with-nested">{{ {alpha: {beta: {gamma: 123}}}|with(['alpha', 'beta', 'gamma'], 456)|json_encode|replace({'"':''}) }}</div> <div class="tt-with-nested">{{ {alpha: {beta: {gamma: 123}}}|with(['alpha', 'beta', 'gamma'], 456)|json_encode|replace({'"':''}) }}</div>
<div class="tt-data-uri-svg">
<img src="{{ '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100" height="50" fill="lime"/></svg>'|data_uri('image/svg+xml') }}" alt="{{ 'Rectangle'|t }}" style="height: 50px;"/>
</div>
<div class="tt-data-uri-iframe">
<iframe src="{{ '<h1>Hello world!</h1>'|data_uri('text/html', {charset: 'UTF-8'}) }}"></iframe>
</div>
<div class="tt-children"> <div class="tt-children">
{%- {%-
set build = { set build = {

2
twig_tweak.api.php

@ -23,6 +23,7 @@ use Twig\TwigTest;
* Twig functions to alter. * Twig functions to alter.
*/ */
function hook_twig_tweak_functions_alter(array &$functions): void { function hook_twig_tweak_functions_alter(array &$functions): void {
// @phpcs:disable
// A simple way to implement lazy loaded global variables. // A simple way to implement lazy loaded global variables.
$callback = static fn (string $name): ?string => $callback = static fn (string $name): ?string =>
match ($name) { match ($name) {
@ -31,6 +32,7 @@ function hook_twig_tweak_functions_alter(array &$functions): void {
default => NULL, default => NULL,
}; };
$functions[] = new TwigFunction('var', $callback); $functions[] = new TwigFunction('var', $callback);
// @phpcs:enable
} }
/** /**

Loading…
Cancel
Save