Problem/Motivation

Currently alt and title are auto generated. This doesn't allow the user to customise the output.

Proposed resolution

Add configuration that allows the user to use tokens to specify where to get the values.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Primsi created an issue. See original summary.

Primsi’s picture

Status: Active » Needs review
FileSize
6.25 KB

Initial work.

Berdir’s picture

Status: Needs review » Needs work
  1. +++ b/src/Plugin/Field/FieldFormatter/SvgFormatter.php
    @@ -128,6 +151,17 @@ class SvgFormatter extends FormatterBase {
    +      '#description' => $this->t('Install token module to see available tokens.'),
    

    we should then unset this description if the token module is installed.

  2. +++ b/src/Plugin/Field/FieldFormatter/SvgFormatter.php
    @@ -138,6 +172,23 @@ class SvgFormatter extends FormatterBase {
    +    if ($this->moduleHandler->moduleExists('token')) {
    +      $form['token_help'] = [
    +        '#theme' => 'token_tree_link',
    +        '#token_types' => ['commerce_order'],
    +      ];
    

    the token types that we have are file and the host entity type, e.g. node or media, which you can get from the field definition.

  3. +++ b/src/Plugin/Field/FieldFormatter/SvgFormatter.php
    @@ -187,18 +245,27 @@ class SvgFormatter extends FormatterBase {
    -          $attributes['alt'] = $alt;
    +          if ($alt_token = $this->getSetting('alt_token')) {
    +            $alt = $this->token->replace($alt_token, ['file' => $file, $parent->getEntityTypeId() => $parent]);
    +          }
    +          $attributes['alt'] = isset($alt) ? $alt : $default_alt;
    

    you can probably prepare the $data argument once and reuse it.. building it almost costs nothing.

    Also not quite sure.. I think like this, with an isset(), you could also just as well keep the $attributes['alt'] assignment above and overwrite it inside the condition. because it will always at least return an empty string. We should also use the clear option in the third argument, because if a field is empty, we should make sure that we don't display the raw token as the alt title.

    A test would be great, shouldn't be too complicated to create e.g. a media entity with a file and two text fields and then test with some tokens, then test a media with and without text in those fields.

Primsi’s picture

Thx for the review.

1. Changed
2. Added logic
3. Changed

Also not quite sure.. I think like this, with an isset(), you could also just as well keep the $attributes['alt']

Not sure if I got correctly this part, but I did change it :)

We should also use the clear option

Added the clear option. The title attribute is still set here though. Not quite sure if we just don't set it or fallback to the auto generated.

A test would be great,

Todo.

Berdir’s picture

> Added the clear option. The title attribute is still set here though. Not quite sure if we just don't set it or fallback to the auto generated.

I wouldn't fall back, if there's no title then we should skip the alt/title attribute. So maybe it does need to be a bit more complicated again, so we only set it if we have a value:

<?php
$alt = $this->getSetting() ? use-setting : default;
if ($alt) {
$attributes['alt'] = $alt;
}

that said, I'd actually go for a more explicit:

$alt = NULL;
if (use token string) {
$alt = ...;
}
elseif (use fallback) {
$alt = ...;
}

if ($alt) {
// set it
}

Also, maybe use alt_string or something like that instead of token, technically you're not actually required to use a token, can be any string or multiple tokens.

Primsi’s picture

Status: Needs work » Needs review
FileSize
11.88 KB
14.68 KB

Added the test and addressed #5

Berdir’s picture

  1. +++ b/svg_formatter.info.yml
    @@ -3,3 +3,5 @@ description: 'SVG Formatter provides support for using SVG images on your websit
     core: 8.x
     package: Field types
    +test_dependencies:
    +  - token:token
    

    I'd add a composer.json with require-dev instead. a test_dependencies change needs to be committed first, require-dev works immediately.

  2. +++ b/tests/src/Functional/SvgFormatterTest.php
    @@ -0,0 +1,202 @@
    +    $render = $renderer->renderRoot($media_build);
    +    $this->assertTrue(strpos($render, 'thisisthealttext'));
    +    $this->assertTrue(strpos($render, 'thisisthetitletext'));
    +
    +    $media->set('field_alt_string', NULL);
    +    $media->set('field_title_string', NULL);
    +    $media->save();
    +
    +    $media_build = $entity_type_manager->getViewBuilder('media')->view($media, 'default', $component);
    +    /** @var \Drupal\Core\Render\RendererInterface $renderer */
    +    $renderer = \Drupal::service('renderer');
    +    $render = $renderer->renderRoot($media_build);
    +    $this->assertFalse(strpos($render, 'thisisthealttext'));
    +    $this->assertFalse(strpos($render, 'thisisthetitletext'));
    +  }
    

    Can we assert the whole thing? alt="thisisthealttext", so that we can specifically assert that there is no empty alt/title attribute in the second case.

Primsi’s picture

Primsi’s picture

Some code style and copycat leftovers.

Berdir’s picture

+++ b/tests/src/Functional/SvgFormatterTest.php
@@ -184,8 +185,10 @@ class SvgFormatterTest extends BrowserTestBase {
     /** @var \Drupal\Core\Render\RendererInterface $renderer */
     $renderer = \Drupal::service('renderer');
     $render = $renderer->renderRoot($media_build);
-    $this->assertTrue(strpos($render, 'thisisthealttext'));
-    $this->assertTrue(strpos($render, 'thisisthetitletext'));
+    $dom_document = Html::load($render->__toString());
+    $xpath = new \DOMXPath($dom_document);
+    $this->assertTrue($xpath->query('//div[contains(@class, "field--name-field-media-file")]//img')->item(0)->getAttribute('alt') == 'thisisthealttext');
+    $this->assertTrue($xpath->query('//div[contains(@class, "field--name-field-media-file")]//img')->item(0)->getAttribute('title') == 'thisisthetitletext');
 

Was thinking that it should be easier to write a CSS Based selector for this, but I guess a bit tricky as you render it through the API. I guess you could also switch the setting to allow access to /media/1, then this could be something like this: $this->assertSession()->elementAttributeContains('css', '.field--name-field-media-file img', 'alt', 'thisisthealttext');

(elementNotExists doesn't exist, but you could do $this->assertFalse($this->assertSession()->elementExists('css', '.field--name-field-media-file img')->hasAttribute('title')); for that.

Primsi’s picture

1. switched approach as suggested in #10
2. using entity repository to get the right translation for token replacement data as suggested in chat
3. minor cosmetic changes

Primsi’s picture

gnikolovski’s picture

Assigned: Unassigned » gnikolovski
Status: Needs review » Reviewed & tested by the community

  • gnikolovski committed fd643f2 on 8.x-1.x authored by Primsi
    Issue #3079043 by Primsi, Berdir, gnikolovski: Add token support for alt...
gnikolovski’s picture

Status: Reviewed & tested by the community » Fixed

Thanks guys!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.