diff --git a/core/modules/image/config/schema/image.schema.yml b/core/modules/image/config/schema/image.schema.yml index 323220b..cb1a4a8 100644 --- a/core/modules/image/config/schema/image.schema.yml +++ b/core/modules/image/config/schema/image.schema.yml @@ -139,6 +139,20 @@ field.formatter.settings.image: type: string label: 'Image style' +field.formatter.settings.image_url: + type: mapping + label: 'Image URL formatter settings' + mapping: + image_style: + type: string + label: 'Image style' + url_link: + type: boolean + label: 'Link to the image URL' + trim_length: + type: integer + label: 'Trim link text length' + field.widget.settings.image_image: type: mapping label: 'Image field display format settings' diff --git a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageUrlFormatter.php b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageUrlFormatter.php new file mode 100644 index 0000000..0a861de --- /dev/null +++ b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageUrlFormatter.php @@ -0,0 +1,145 @@ + '', + 'url_link' => '', + 'trim_length' => '80', + ]; + } + + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, FormStateInterface $form_state) { + $element = parent::settingsForm($form, $form_state); + + $element['url_link'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Provide link'), + '#description' => $this->t('If checked, the URL to image will get a click-able link otherwise, the plain URL will be displayed.'), + '#default_value' => $this->getSetting('url_link'), + ]; + $element['trim_length'] = [ + '#type' => 'number', + '#title' => $this->t('Trim link text length'), + '#field_suffix' => $this->t('characters'), + '#default_value' => $this->getSetting('trim_length'), + '#min' => 1, + '#description' => $this->t('Leave blank to allow unlimited link text lengths.'), + '#states' => [ + 'invisible' => [ + ":input[name=\"fields[{$this->fieldDefinition->getName()}][settings_edit_form][settings][url_link]\"]" => ['checked' => FALSE], + ], + ], + ]; + + unset($element['image_link']);; + + return $element; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary() { + $summary = []; + + $image_styles = image_style_options(FALSE); + // Unset possible 'No defined styles' option. + unset($image_styles['']); + // Styles could be lost because of enabled/disabled modules that defines + // their styles in code. + $image_style_setting = $this->getSetting('image_style'); + if (isset($image_styles[$image_style_setting])) { + $summary[] = $this->t('Image style: @style', ['@style' => $image_styles[$image_style_setting]]); + } + else { + $summary[] = $this->t('Original image'); + } + + return $summary; + } + + /** + * {@inheritdoc} + */ + public function viewElements(FieldItemListInterface $items, $langcode) { + $elements = []; + $settings = $this->getSettings(); + + /** + * @var \Drupal\file\Entity\File[] $images + * @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $items + */ + if (empty($images = $this->getEntitiesToView($items, $langcode))) { + // Early opt-out if the field is empty. + return $elements; + } + + /** @var \Drupal\image\ImageStyleInterface $image_style */ + $image_style = $this->imageStyleStorage->load($settings['image_style']); + + foreach ($images as $delta => $image) { + $image_uri = $image->getFileUri(); + $url = $image_style ? $image_style->buildUrl($image_uri) : file_create_url($image_uri); + + // Add cacheable metadata from the image and image style. + $cacheable_metadata = CacheableMetadata::createFromObject($image); + if ($image_style) { + $cacheable_metadata->addCacheableDependency(CacheableMetadata::createFromObject($image_style)); + } + + if ($settings['url_link']) { + // Linked url. + $link_title = $url; + if (!empty($settings['trim_length'])) { + $link_title = Unicode::truncate($link_title, $settings['trim_length'], FALSE, TRUE); + } + $elements[$delta] = [ + '#type' => 'link', + '#url' => Url::fromUri(file_create_url($url)), + '#title' => $link_title, + ]; + } + else { + // Plain text URL. + $elements[$delta] = ['#markup' => $url]; + } + $cacheable_metadata->applyTo($elements[$delta]); + } + + return $elements; + } + +} diff --git a/core/modules/image/src/Tests/ImageFieldDisplayTest.php b/core/modules/image/src/Tests/ImageFieldDisplayTest.php index 666a791..f30d273 100644 --- a/core/modules/image/src/Tests/ImageFieldDisplayTest.php +++ b/core/modules/image/src/Tests/ImageFieldDisplayTest.php @@ -2,6 +2,7 @@ namespace Drupal\image\Tests; +use Drupal\Component\Utility\Unicode; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\field\Entity\FieldStorageConfig; use Drupal\user\RoleInterface; @@ -88,6 +89,7 @@ function _testImageFieldFormatters($scheme) { // Save node. $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $alt); $node_storage->resetCache(array($nid)); + /** @var \Drupal\node\Entity\Node $node */ $node = $node_storage->load($nid); // Test that the default formatter is being used. @@ -199,6 +201,38 @@ function _testImageFieldFormatters($scheme) { $this->drupalGet(ImageStyle::load('thumbnail')->buildUrl($image_uri)); $this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.'); } + + // Test the image URL formatter without an image style. + $display_options = [ + 'type' => 'image_url', + 'settings' => [ + 'image_style' => '', + 'url_link' => FALSE, + 'trim_length' => 80, + ], + ]; + $expected_url = file_create_url($image_uri); + $this->assertEqual($expected_url, $node->{$field_name}->view($display_options)[0]['#markup']); + + // Test the image URL formatter without an image style. + $display_options['settings']['image_style'] = 'thumbnail'; + $expected_url = ImageStyle::load('thumbnail')->buildUrl($image_uri); + $this->assertEqual($expected_url, $node->{$field_name}->view($display_options)[0]['#markup']); + + // Test the image URL formatter with an image style with link. + $display_options['settings']['url_link'] = TRUE; + $display_options['settings']['trim_length'] = 0; + + $expected_output = '' . $expected_url . ''; + $this->assertEqual($expected_output, (string) $renderer->renderRoot($node->{$field_name}->view($display_options)[0])); + + // Test the image URL formatter with an image style with link and trimmed + // link text. + $display_options['settings']['trim_length'] = 10; + + $expected_link_text = Unicode::truncate($expected_url, 10, FALSE, TRUE); + $expected_output = '' . $expected_link_text . ''; + $this->assertEqual($expected_output, (string) $renderer->renderRoot($node->{$field_name}->view($display_options)[0])); } /**