From f47beed63c7ebd86e6d69d329774f7819fa7b3a0 Mon Sep 17 00:00:00 2001 From: orakili Date: Wed, 30 Aug 2023 19:01:05 +0000 Subject: [PATCH 1/5] feat: add image optimize webp module Refs: RW-803 --- ...pi_optimize_webp-imagemagick-toolkit.patch | 60 +++++++++++++++++++ ...eapi_optimize_webp-webp-source-image.patch | 23 +++++++ composer.json | 3 +- composer.lock | 51 +++++++++++++++- composer.patches.json | 4 ++ 5 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 PATCHES/imageapi_optimize_webp-imagemagick-toolkit.patch create mode 100644 PATCHES/imageapi_optimize_webp-webp-source-image.patch diff --git a/PATCHES/imageapi_optimize_webp-imagemagick-toolkit.patch b/PATCHES/imageapi_optimize_webp-imagemagick-toolkit.patch new file mode 100644 index 000000000..b2e0ce5df --- /dev/null +++ b/PATCHES/imageapi_optimize_webp-imagemagick-toolkit.patch @@ -0,0 +1,60 @@ +diff --git a/src/Plugin/ImageAPIOptimizeProcessor/WebP.php b/src/Plugin/ImageAPIOptimizeProcessor/WebP.php +index 070c6fe..20d8bd5 100644 +--- a/src/Plugin/ImageAPIOptimizeProcessor/WebP.php ++++ b/src/Plugin/ImageAPIOptimizeProcessor/WebP.php +@@ -6,6 +6,8 @@ use Drupal\Core\Form\FormStateInterface; + use Drupal\imageapi_optimize\ConfigurableImageAPIOptimizeProcessorBase; + + /** ++ * WebP conversion processor. ++ * + * @ImageAPIOptimizeProcessor( + * id = "imageapi_optimize_webp", + * label = @Translation("WebP Deriver"), +@@ -18,14 +20,31 @@ class WebP extends ConfigurableImageAPIOptimizeProcessorBase { + * {@inheritdoc} + */ + public function applyToImage($image_uri) { +- $source_image = $this->imageFactory->get($image_uri, 'gd'); ++ if (!in_array('webp', $this->imageFactory->getSupportedExtensions())) { ++ return FALSE; ++ } ++ $toolkit_id = $this->imageFactory->getToolkitId(); ++ $source_image = $this->imageFactory->get($image_uri, $toolkit_id); + if ($source_image) { + $destination = $image_uri . '.webp'; +- // @todo: Add try/catch. +- imagewebp($source_image->getToolkit()->getResource(), $destination, $this->configuration['quality']); +- // Fix issue where sometimes image fails to generate. +- if (filesize($destination) % 2 == 1) { +- file_put_contents($destination, "\0", FILE_APPEND); ++ try { ++ if ($toolkit_id == 'imagemagick') { ++ $source_image->convert('webp'); ++ $source_image->save($destination); ++ } ++ elseif ($toolkit_id == 'gd') { ++ imagewebp($source_image->getToolkit()->getResource(), $destination, $this->configuration['quality']); ++ } ++ else { ++ return FALSE; ++ } ++ // Fix issue where sometimes image fails to generate. ++ if (filesize($destination) % 2 == 1) { ++ file_put_contents($destination, "\0", FILE_APPEND); ++ } ++ } ++ catch (\Exception $exception) { ++ return FALSE; + } + return TRUE; + } +@@ -45,7 +64,7 @@ class WebP extends ConfigurableImageAPIOptimizeProcessorBase { + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { +- // @todo: Add ability to pick which image types allow derivatives. ++ // @todo Add ability to pick which image types allow derivatives. + $form['quality'] = [ + '#type' => 'number', + '#title' => $this->t('Image quality'), diff --git a/PATCHES/imageapi_optimize_webp-webp-source-image.patch b/PATCHES/imageapi_optimize_webp-webp-source-image.patch new file mode 100644 index 000000000..61baf5159 --- /dev/null +++ b/PATCHES/imageapi_optimize_webp-webp-source-image.patch @@ -0,0 +1,23 @@ +diff --git a/src/Controller/ImageStyleDownloadController.php b/src/Controller/ImageStyleDownloadController.php +index c8c9d67..3bb45af 100644 +--- a/src/Controller/ImageStyleDownloadController.php ++++ b/src/Controller/ImageStyleDownloadController.php +@@ -25,9 +25,17 @@ class ImageStyleDownloadController extends CoreImageStyleDownloadController { + */ + public function lookupSourceImage($image_uri) { + $source_image = substr($image_uri, 0, strrpos($image_uri, ".")); +- if($source_image . '.webp' === $image_uri) { ++ // Handle image URI in the form `name.webp` in which case it is already ++ // the source image. ++ if (pathinfo($source_image, \PATHINFO_EXTENSION) === '') { ++ return $image_uri; ++ } ++ // Handle image URI in the form `name.ext.webp` in which case `name.ext` is ++ // the source image. ++ elseif ($source_image . '.webp' === $image_uri) { + return $source_image; + } ++ return NULL; + } + + /** diff --git a/composer.json b/composer.json index df067a35f..1d56a5406 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "cweagans/composer-patches": "^1.7", "drupal/admin_denied": "^2.0", "drupal/allowed_formats": "^2.0", - "drupal/ckeditor": "*", + "drupal/ckeditor": "^1.0", "drupal/classy": "^1.0", "drupal/components": "^3.0@beta", "drupal/config_filter": "^2.2", @@ -38,6 +38,7 @@ "drupal/google_tag": "^1.6", "drupal/guidelines": "^1.0", "drupal/imageapi_optimize_binaries": "^1.0@beta", + "drupal/imageapi_optimize_webp": "^2.0", "drupal/imagemagick": "^3.4", "drupal/inline_entity_form": "^1.0@rc", "drupal/mailsystem": "^4.4", diff --git a/composer.lock b/composer.lock index 47544eb0d..8ab004a4e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0ea5267b5ce638d1d5f3057e0fdeba79", + "content-hash": "706c99bd199323e0e46bd92e36ec0f88", "packages": [ { "name": "asm89/stack-cors", @@ -3461,6 +3461,55 @@ "source": "https://git.drupalcode.org/project/imageapi_optimize_binaries" } }, + { + "name": "drupal/imageapi_optimize_webp", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/imageapi_optimize_webp.git", + "reference": "2.0.0" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/imageapi_optimize_webp-2.0.0.zip", + "reference": "2.0.0", + "shasum": "c680728a66b58c16dc99df9e972b9094d1dc459b" + }, + "require": { + "drupal/core": "^8 || ^9 || ^10", + "drupal/imageapi_optimize": "*" + }, + "type": "drupal-module", + "extra": { + "drupal": { + "version": "2.0.0", + "datestamp": "1681161804", + "security-coverage": { + "status": "covered", + "message": "Covered by Drupal's security advisory policy" + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "michaellander", + "homepage": "https://www.drupal.org/user/636494" + } + ], + "description": "Add WebP support to Image API", + "homepage": "https://www.drupal.org/project/imageapi_optimize_webp", + "keywords": [ + "Drupal" + ], + "support": { + "source": "http://cgit.drupalcode.org/imageapi_optimize_webp", + "issues": "https://www.drupal.org/project/issues/imageapi_optimize_webp" + } + }, { "name": "drupal/imagemagick", "version": "3.4.0", diff --git a/composer.patches.json b/composer.patches.json index 359a534e1..e8244a072 100644 --- a/composer.patches.json +++ b/composer.patches.json @@ -9,6 +9,10 @@ "drupal/guidelines": { "Drupal 10 compatibility": "PATCHES/guidelines-drupal-10-compatibility.patch" }, + "drupal/imageapi_optimize_webp": { + "Fix derivatives for webp source images": "PATCHES/imageapi_optimize_webp-webp-source-image.patch", + "Support imagemagick toolkit": "PATCHES/imageapi_optimize_webp-imagemagick-toolkit.patch" + }, "drupal/maintenance200": { "Drupal 10 compatibility": "PATCHES/maintenance200-drupal-10-compatibility.patch" }, From 5a1819d232ff5ffea520417c660344799f82865b Mon Sep 17 00:00:00 2001 From: orakili Date: Wed, 30 Aug 2023 19:03:27 +0000 Subject: [PATCH 2/5] feat: enable image optimize webp modules Refs: RW-803 --- config/core.extension.yml | 2 ++ config/imageapi_optimize.pipeline.webp.yml | 26 ++++++++++++++++++++++ config/imageapi_optimize.settings.yml | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 config/imageapi_optimize.pipeline.webp.yml diff --git a/config/core.extension.yml b/config/core.extension.yml index 01a38fb94..ea01719d9 100644 --- a/config/core.extension.yml +++ b/config/core.extension.yml @@ -28,6 +28,8 @@ module: image: 0 imageapi_optimize: 0 imageapi_optimize_binaries: 0 + imageapi_optimize_webp: 0 + imageapi_optimize_webp_responsive: 0 imagemagick: 0 inline_entity_form: 0 inline_form_errors: 0 diff --git a/config/imageapi_optimize.pipeline.webp.yml b/config/imageapi_optimize.pipeline.webp.yml new file mode 100644 index 000000000..22b464bb1 --- /dev/null +++ b/config/imageapi_optimize.pipeline.webp.yml @@ -0,0 +1,26 @@ +uuid: f73a800f-44db-46f4-b6e8-e2eff11e1e11 +langcode: en +status: true +dependencies: + module: + - imageapi_optimize_binaries + - imageapi_optimize_webp +name: webp +label: Webp +processors: + 17c18933-5d67-4a5b-8a1f-4666eb7acabf: + id: imageapi_optimize_webp + data: + quality: '75' + weight: 1 + uuid: 17c18933-5d67-4a5b-8a1f-4666eb7acabf + e9fab1af-a730-4393-846b-5d254a40fde8: + id: pngquant + data: + manual_executable_path: '' + speed: 3 + quality: + min: 90 + max: 99 + weight: 2 + uuid: e9fab1af-a730-4393-846b-5d254a40fde8 diff --git a/config/imageapi_optimize.settings.yml b/config/imageapi_optimize.settings.yml index afddbaefe..7f083c53a 100644 --- a/config/imageapi_optimize.settings.yml +++ b/config/imageapi_optimize.settings.yml @@ -1,3 +1,3 @@ _core: default_config_hash: MTm0uqe2B71zGYpOt10vRcS7pf9m92Yy2P4cnTXbSR0 -default_pipeline: local_binaries +default_pipeline: webp From 5cc9bff853c93df90b9df6b8bc5c2f8797224d42 Mon Sep 17 00:00:00 2001 From: orakili Date: Wed, 30 Aug 2023 19:04:17 +0000 Subject: [PATCH 3/5] feat: set responsive image styles Refs: RW-803 --- .../responsive_image.styles.announcement.yml | 18 +++++++++++ config/responsive_image.styles.large.yml | 30 +++++++++++++++++++ config/responsive_image.styles.medium.yml | 24 +++++++++++++++ config/responsive_image.styles.small.yml | 18 +++++++++++ config/responsive_image.styles.thumbnail.yml | 18 +++++++++++ .../common_design_subtheme.breakpoints.yml | 28 +++++++++++++++++ 6 files changed, 136 insertions(+) create mode 100644 config/responsive_image.styles.announcement.yml create mode 100644 config/responsive_image.styles.large.yml create mode 100644 config/responsive_image.styles.medium.yml create mode 100644 config/responsive_image.styles.small.yml create mode 100644 config/responsive_image.styles.thumbnail.yml create mode 100644 html/themes/custom/common_design_subtheme/common_design_subtheme.breakpoints.yml diff --git a/config/responsive_image.styles.announcement.yml b/config/responsive_image.styles.announcement.yml new file mode 100644 index 000000000..360e59ebf --- /dev/null +++ b/config/responsive_image.styles.announcement.yml @@ -0,0 +1,18 @@ +uuid: 30afe701-645d-471b-a397-2e83987cb5e2 +langcode: en +status: true +dependencies: + config: + - image.style.announcement + theme: + - common_design_subtheme +id: announcement +label: Announcement +image_style_mappings: + - + image_mapping_type: image_style + image_mapping: announcement + breakpoint_id: common_design.small + multiplier: 1x +breakpoint_group: common_design_subtheme +fallback_image_style: announcement diff --git a/config/responsive_image.styles.large.yml b/config/responsive_image.styles.large.yml new file mode 100644 index 000000000..4bd97b0ef --- /dev/null +++ b/config/responsive_image.styles.large.yml @@ -0,0 +1,30 @@ +uuid: 457de771-4805-442d-a5c3-ce8463405ab9 +langcode: en +status: true +dependencies: + config: + - image.style.large + - image.style.medium + - image.style.small + theme: + - common_design_subtheme +id: large +label: Large +image_style_mappings: + - + image_mapping_type: image_style + image_mapping: large + breakpoint_id: common_design.large + multiplier: 1x + - + image_mapping_type: image_style + image_mapping: medium + breakpoint_id: common_design.medium + multiplier: 1x + - + image_mapping_type: image_style + image_mapping: small + breakpoint_id: common_design.small + multiplier: 1x +breakpoint_group: common_design_subtheme +fallback_image_style: small diff --git a/config/responsive_image.styles.medium.yml b/config/responsive_image.styles.medium.yml new file mode 100644 index 000000000..8a03efac5 --- /dev/null +++ b/config/responsive_image.styles.medium.yml @@ -0,0 +1,24 @@ +uuid: a83c71ef-172d-43a4-b773-45ba58e7ec82 +langcode: en +status: true +dependencies: + config: + - image.style.medium + - image.style.small + theme: + - common_design_subtheme +id: medium +label: Medium +image_style_mappings: + - + image_mapping_type: image_style + image_mapping: medium + breakpoint_id: common_design.medium + multiplier: 1x + - + image_mapping_type: image_style + image_mapping: small + breakpoint_id: common_design.small + multiplier: 1x +breakpoint_group: common_design_subtheme +fallback_image_style: small diff --git a/config/responsive_image.styles.small.yml b/config/responsive_image.styles.small.yml new file mode 100644 index 000000000..27a1faca3 --- /dev/null +++ b/config/responsive_image.styles.small.yml @@ -0,0 +1,18 @@ +uuid: f3c4de78-bed4-4964-bc12-374fb64fa7c2 +langcode: en +status: true +dependencies: + config: + - image.style.small + theme: + - common_design_subtheme +id: small +label: Small +image_style_mappings: + - + image_mapping_type: image_style + image_mapping: small + breakpoint_id: common_design.small + multiplier: 1x +breakpoint_group: common_design_subtheme +fallback_image_style: small diff --git a/config/responsive_image.styles.thumbnail.yml b/config/responsive_image.styles.thumbnail.yml new file mode 100644 index 000000000..afc1bfc45 --- /dev/null +++ b/config/responsive_image.styles.thumbnail.yml @@ -0,0 +1,18 @@ +uuid: 7976cfe7-bf51-46f2-b13a-b16d9d074534 +langcode: en +status: true +dependencies: + config: + - image.style.thumbnail + theme: + - common_design_subtheme +id: thumbnail +label: Thumbnail +image_style_mappings: + - + image_mapping_type: image_style + image_mapping: thumbnail + breakpoint_id: common_design.small + multiplier: 1x +breakpoint_group: common_design_subtheme +fallback_image_style: thumbnail diff --git a/html/themes/custom/common_design_subtheme/common_design_subtheme.breakpoints.yml b/html/themes/custom/common_design_subtheme/common_design_subtheme.breakpoints.yml new file mode 100644 index 000000000..736a19fa1 --- /dev/null +++ b/html/themes/custom/common_design_subtheme/common_design_subtheme.breakpoints.yml @@ -0,0 +1,28 @@ +common_design.small: + label: small + mediaQuery: "(min-width: 0px)" + weight: 1 + multipliers: + - 1x + - 2x +common_design.medium: + label: medium + mediaQuery: "(min-width: 220px)" + weight: 1 + multipliers: + - 1x + - 2x +common_design.large: + label: large + mediaQuery: "(min-width: 450px)" + weight: 1 + multipliers: + - 1x + - 2x +common_design.extra_large: + label: extra large + mediaQuery: "(min-width: 700px)" + weight: 1 + multipliers: + - 1x + - 2x From 02ced54a58de7bacf2793a0af711b7dad740e291 Mon Sep 17 00:00:00 2001 From: orakili Date: Wed, 30 Aug 2023 19:08:24 +0000 Subject: [PATCH 4/5] feat: use responsive image theme where relevant instead of image_style one Refs: RW-803 --- .../reliefweb_entities/src/Entity/Report.php | 2 +- .../reliefweb-entities-entity-image.html.twig | 6 ++-- .../reliefweb_files/reliefweb_files.module | 33 ++++++++++++++----- .../Plugin/Field/FieldType/ReliefWebFile.php | 10 +++--- .../reliefweb-homepage-announcement.html.twig | 6 ++-- .../src/Services/ReportRiver.php | 30 +++++++++-------- ...web-rivers-river-article--report.html.twig | 14 +++++++- .../components/rw-article/rw-article.css | 5 ++- ...reliefweb-file-list--interactive.html.twig | 0 .../reliefweb-file-list.html.twig | 0 10 files changed, 70 insertions(+), 36 deletions(-) rename html/themes/custom/common_design_subtheme/templates/rw-modules/{reliefweb_docstore => reliefweb_files}/reliefweb-file-list--interactive.html.twig (100%) rename html/themes/custom/common_design_subtheme/templates/rw-modules/{reliefweb_docstore => reliefweb_files}/reliefweb-file-list.html.twig (100%) diff --git a/html/modules/custom/reliefweb_entities/src/Entity/Report.php b/html/modules/custom/reliefweb_entities/src/Entity/Report.php index 805f5ff96..7f17a5632 100644 --- a/html/modules/custom/reliefweb_entities/src/Entity/Report.php +++ b/html/modules/custom/reliefweb_entities/src/Entity/Report.php @@ -183,7 +183,7 @@ public function getAttachments(?array $build = NULL) { $build['#attributes']['class'][] = 'rw-attachment--map'; foreach ($build['#list'] as &$item) { if (isset($item['preview'])) { - $item['preview']['#style_name'] = 'large'; + $item['preview']['#responsive_image_style_id'] = 'large'; } $item['label'] = $label; } diff --git a/html/modules/custom/reliefweb_entities/templates/reliefweb-entities-entity-image.html.twig b/html/modules/custom/reliefweb_entities/templates/reliefweb-entities-entity-image.html.twig index 5401b578c..73def854d 100644 --- a/html/modules/custom/reliefweb_entities/templates/reliefweb-entities-entity-image.html.twig +++ b/html/modules/custom/reliefweb_entities/templates/reliefweb-entities-entity-image.html.twig @@ -25,11 +25,11 @@ }}> {% if style is not empty %} {{ render_var({ - '#theme': 'image_style', - '#style_name': style, + '#theme': 'responsive_image', + '#responsive_image_style_id': style, '#uri': image.uri, - '#alt': image.alt, '#attributes': { + 'alt': image.alt, 'class': ['rw-entity-image__image'], 'loading': image.loading is not empty ? image.loading : loading, }, diff --git a/html/modules/custom/reliefweb_files/reliefweb_files.module b/html/modules/custom/reliefweb_files/reliefweb_files.module index e2996e100..d595f84ac 100644 --- a/html/modules/custom/reliefweb_files/reliefweb_files.module +++ b/html/modules/custom/reliefweb_files/reliefweb_files.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Template\Attribute; use Drupal\file\Entity\File; use Drupal\reliefweb_files\Plugin\Field\FieldType\ReliefWebFile; use Drupal\reliefweb_files\Plugin\Field\FieldType\ReliefWebFileList; @@ -56,17 +57,33 @@ function reliefweb_files_theme() { } /** - * Implemenents hook_preprocess_HOOK() for "image_style". + * Implemenents hook_preprocess_HOOK() for "responsive_image". */ -function reliefweb_files_preprocess_image_style__preview(&$variables) { - // We add a parameter to the image derivative URL to ensure the correct +function reliefweb_files_preprocess_responsive_image__preview(&$variables) { + // We add a parameter to the image derivative URLs to ensure the correct // version is served. - if (isset($variables['image']['#attributes']['data-version'])) { - $version = $variables['image']['#attributes']['data-version']; - $uri = $variables['image']['#uri']; + if (isset($variables['attributes']['data-version'])) { + $version = $variables['attributes']['data-version']; + if (isset($variables['sources'])) { + foreach ($variables['sources'] as $source) { + if ($source instanceof Attribute && $source->offsetExists('srcset')) { + $srcset = (string) $source->offsetGet('srcset'); + $srcset = preg_replace_callback('#(?(https?://[^/]+)?/[^ ,]+)#', function ($matches) use ($version) { + return $matches['uri'] . (strpos($matches['uri'], '?') !== FALSE ? '&' : '?') . $version; + }, $srcset); + $source->offsetSet('srcset', $srcset); + } + } + } + unset($variables['attributes']['data-version']); + } + + if (isset($variables['img_element']['#attributes']['data-version'])) { + $version = $variables['img_element']['#attributes']['data-version']; + $uri = $variables['img_element']['#uri']; $uri .= (strpos($uri, '?') !== FALSE ? '&' : '?') . $version; - $variables['image']['#uri'] = $uri; - unset($variables['image']['#attributes']['data-version']); + $variables['img_element']['#uri'] = $uri; + unset($variables['img_element']['#attributes']['data-version']); } } diff --git a/html/modules/custom/reliefweb_files/src/Plugin/Field/FieldType/ReliefWebFile.php b/html/modules/custom/reliefweb_files/src/Plugin/Field/FieldType/ReliefWebFile.php index d8d0bb703..34801f427 100644 --- a/html/modules/custom/reliefweb_files/src/Plugin/Field/FieldType/ReliefWebFile.php +++ b/html/modules/custom/reliefweb_files/src/Plugin/Field/FieldType/ReliefWebFile.php @@ -670,13 +670,13 @@ public function renderPreview($style = 'small', $generate = FALSE) { } return [ - '#theme' => 'image_style__preview', - '#style_name' => $style, + '#theme' => 'responsive_image__preview', + '#responsive_image_style_id' => $style, '#uri' => $uri, - '#alt' => $this->t('Preview of @file_name', [ - '@file_name' => $this->getFileName(), - ]), '#attributes' => [ + 'alt' => $this->t('Preview of @file_name', [ + '@file_name' => $this->getFileName(), + ]), 'class' => ['rw-file-preview'], 'data-version' => implode('-', [ // Once the file is saved it will have a revision ID, until then to diff --git a/html/modules/custom/reliefweb_homepage/templates/reliefweb-homepage-announcement.html.twig b/html/modules/custom/reliefweb_homepage/templates/reliefweb-homepage-announcement.html.twig index cc20d82f2..6e83f8a4a 100644 --- a/html/modules/custom/reliefweb_homepage/templates/reliefweb-homepage-announcement.html.twig +++ b/html/modules/custom/reliefweb_homepage/templates/reliefweb-homepage-announcement.html.twig @@ -32,11 +32,11 @@ {{ render_var({ - '#theme': 'image_style', - '#style_name': 'announcement', + '#theme': 'responsive_image', + '#responsive_image_style_id': 'announcement', '#uri': image.url, - '#alt': image.alt, '#attributes': { + 'alt': image.alt, 'class': ['rw-homepage-announcement__image'], 'loading': 'eager', }, diff --git a/html/modules/custom/reliefweb_rivers/src/Services/ReportRiver.php b/html/modules/custom/reliefweb_rivers/src/Services/ReportRiver.php index dbfe6f771..526e843bd 100644 --- a/html/modules/custom/reliefweb_rivers/src/Services/ReportRiver.php +++ b/html/modules/custom/reliefweb_rivers/src/Services/ReportRiver.php @@ -444,19 +444,21 @@ public function parseApiData(array $api_data, $view = '') { } // Attachment preview. - if (!empty($fields['file'][0]['preview'])) { + if (!empty($fields['file'][0]['preview']['url'])) { $preview = $fields['file'][0]['preview']; - $url = $preview['url-thumb'] ?? $preview['url-small'] ?? ''; - if (!empty($url)) { - $version = $preview['version'] ?? $fields['file'][0]['id'] ?? 0; - $data['preview'] = [ - 'url' => UrlHelper::stripDangerousProtocols($url) . '?' . $version, - // We don't have any good label/description for the file - // previews so we use an empty alt to mark them as decorative - // so that assistive technologies will ignore them. - 'alt' => '', - ]; - } + $uri = UrlHelper::getImageUriFromUrl($preview['url']); + $version = $preview['version'] ?? $fields['file'][0]['id'] ?? 0; + $dimensions = @getimagesize($uri) ?? []; + $data['preview'] = [ + 'uri' => $uri, + 'version' => $version, + // We don't have any good label/description for the file + // previews so we use an empty alt to mark them as decorative + // so that assistive technologies will ignore them. + 'alt' => '', + 'width' => $dimensions[0] ?? NULL, + 'height' => $dimensions[1] ?? NULL, + ]; } // Headline image. @@ -467,8 +469,8 @@ public function parseApiData(array $api_data, $view = '') { 'uri' => UrlHelper::getImageUriFromUrl($image['url']), 'alt' => $image['caption'] ?? '', 'copyright' => trim($image['copyright'] ?? '', " \n\r\t\v\0@"), - 'width' => $image['width'] ?? 0, - 'height' => $image['height'] ?? 0, + 'width' => $image['width'] ?? NULL, + 'height' => $image['height'] ?? NULL, ]; } diff --git a/html/modules/custom/reliefweb_rivers/templates/reliefweb-rivers-river-article--report.html.twig b/html/modules/custom/reliefweb_rivers/templates/reliefweb-rivers-river-article--report.html.twig index c0ffab09d..e1173d45f 100644 --- a/html/modules/custom/reliefweb_rivers/templates/reliefweb-rivers-river-article--report.html.twig +++ b/html/modules/custom/reliefweb_rivers/templates/reliefweb-rivers-river-article--report.html.twig @@ -63,7 +63,19 @@ {% if entity.summary is not empty or entity.preview is not empty %}
{% if entity.preview is not empty %} - {{ entity.preview.alt ?? '' }} + {{ render_var({ + '#theme': 'responsive_image__preview', + '#responsive_image_style_id': attributes.hasClass('rw-river-article--card') ? 'thumbnail' : 'small', + '#uri': entity.preview.uri, + '#attributes': { + 'alt': entity.preview.alt ?? '', + 'class': ['rw-river-article__preview'], + 'loading': 'lazy', + 'data-version': entity.preview.version ?? '', + }, + '#width': entity.preview.width, + '#height': entity.preview.height + }) }} {% endif %} {% if entity.summary is not empty %}

{{ entity.summary }}

diff --git a/html/themes/custom/common_design_subtheme/components/rw-article/rw-article.css b/html/themes/custom/common_design_subtheme/components/rw-article/rw-article.css index ee41844bf..7e628f55f 100644 --- a/html/themes/custom/common_design_subtheme/components/rw-article/rw-article.css +++ b/html/themes/custom/common_design_subtheme/components/rw-article/rw-article.css @@ -54,11 +54,14 @@ /* Article with a thumbnail preview (typically Map and Infographic). */ .rw-river-article .rw-river-article__content img { float: left; + width: auto; + max-width: none; max-height: 118px; margin: 2px 20px 0 0; border: 1px solid var(--cd-reliefweb-brand-grey--light); } -.rw-river-article .rw-river-article__content img + p { +.rw-river-article .rw-river-article__content img + p, +.rw-river-article .rw-river-article__content picture + p { margin-top: 0; } diff --git a/html/themes/custom/common_design_subtheme/templates/rw-modules/reliefweb_docstore/reliefweb-file-list--interactive.html.twig b/html/themes/custom/common_design_subtheme/templates/rw-modules/reliefweb_files/reliefweb-file-list--interactive.html.twig similarity index 100% rename from html/themes/custom/common_design_subtheme/templates/rw-modules/reliefweb_docstore/reliefweb-file-list--interactive.html.twig rename to html/themes/custom/common_design_subtheme/templates/rw-modules/reliefweb_files/reliefweb-file-list--interactive.html.twig diff --git a/html/themes/custom/common_design_subtheme/templates/rw-modules/reliefweb_docstore/reliefweb-file-list.html.twig b/html/themes/custom/common_design_subtheme/templates/rw-modules/reliefweb_files/reliefweb-file-list.html.twig similarity index 100% rename from html/themes/custom/common_design_subtheme/templates/rw-modules/reliefweb_docstore/reliefweb-file-list.html.twig rename to html/themes/custom/common_design_subtheme/templates/rw-modules/reliefweb_files/reliefweb-file-list.html.twig From f116d48c94ed8f5b9b196e110c46f912c92a9fd4 Mon Sep 17 00:00:00 2001 From: orakili Date: Thu, 31 Aug 2023 01:26:15 +0000 Subject: [PATCH 5/5] chore: patch stage_file_proxy for better webp support Refs: RW-803 --- ..._file_proxy-webp-support-fix-3171559.patch | 26 +++++++++++++++++++ composer.patches.json | 3 +++ 2 files changed, 29 insertions(+) create mode 100644 PATCHES/stage_file_proxy-webp-support-fix-3171559.patch diff --git a/PATCHES/stage_file_proxy-webp-support-fix-3171559.patch b/PATCHES/stage_file_proxy-webp-support-fix-3171559.patch new file mode 100644 index 000000000..deab9e606 --- /dev/null +++ b/PATCHES/stage_file_proxy-webp-support-fix-3171559.patch @@ -0,0 +1,26 @@ +diff --git a/src/EventSubscriber/StageFileProxySubscriber.php b/src/EventSubscriber/StageFileProxySubscriber.php +index 63061b7..daedfbc 100644 +--- a/src/EventSubscriber/StageFileProxySubscriber.php ++++ b/src/EventSubscriber/StageFileProxySubscriber.php +@@ -144,10 +144,9 @@ class StageFileProxySubscriber implements EventSubscriberInterface { + $paths = [$relative_path]; + + // Webp support. +- $is_webp = FALSE; +- if (strpos($relative_path, '.webp')) { ++ if (str_ends_with($relative_path, '.webp')) { + $paths[] = str_replace('.webp', '', $relative_path); +- $is_webp = TRUE; ++ $paths = array_reverse($paths); + } + + foreach ($paths as $relative_path) { +@@ -163,7 +162,7 @@ class StageFileProxySubscriber implements EventSubscriberInterface { + // Is this imagecache? Request the root file and let imagecache resize. + // We check this first so locally added files have precedence. + $original_path = $this->manager->styleOriginalPath($relative_path, TRUE); +- if ($original_path && !$is_webp) { ++ if ($original_path) { + if (file_exists($original_path)) { + // Imagecache can generate it without our help. + return; diff --git a/composer.patches.json b/composer.patches.json index e8244a072..ee60a8d09 100644 --- a/composer.patches.json +++ b/composer.patches.json @@ -19,6 +19,9 @@ "drupal/pathauto": { "PHP 8.2 compatibility": "PATCHES/pathauto-php-82-compatibility.patch" }, + "drupal/stage_file_proxy": { + "Webp support fix": "PATCHES/stage_file_proxy-webp-support-fix-3171559.patch" + }, "drupal/username_enumeration_prevention": { "Avoid leaking the path via Drupal.settings json": "PATCHES/username_enumeration_prevention-user-login-block-form-3312288.patch" },