From 6adb095267373c6564e3ba56af56ccf462341447 Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Tue, 12 Nov 2024 21:16:17 -0500 Subject: [PATCH 1/8] Adds sbf_file_content extension works like this sbf_file_content("uuid_of_the_node", "uuid_of_the_file", "thename.jsonld"); Will return the content of a file if found/matches one of the mimetypes defined as valid for our metadata displays, now defined as constants at CONST ALLOWED_MIMETYPES = [ 'text/html' => 'HTML', 'application/json' => 'JSON', 'application/ld+json' => 'JSON-LD', 'application/xml' => 'XML', 'text/text' => 'TEXT', 'text/turtle' => 'RDF/TURTLE', 'text/csv' => 'CSV', ]; an error message in case of exception or an empty string if the file does not exist, the user has no permission, is not of an allowed type, etc (avoiding as much as possible errors) @alliomeria i am truly smartz! (and modest too!) --- format_strawberryfield.services.yml | 2 +- src/Entity/MetadataDisplayEntity.php | 20 ++++---- src/TwigExtension.php | 68 ++++++++++++++++++++++++++-- 3 files changed, 76 insertions(+), 14 deletions(-) diff --git a/format_strawberryfield.services.yml b/format_strawberryfield.services.yml index a5d79145..d8137777 100644 --- a/format_strawberryfield.services.yml +++ b/format_strawberryfield.services.yml @@ -3,7 +3,7 @@ services: class: Drupal\format_strawberryfield\TwigExtension tags: - {name: twig.extension} - arguments: ['@renderer', '@plugin.manager.search_api.parse_mode'] + arguments: ['@renderer', '@plugin.manager.search_api.parse_mode', '@request_stack', '@kernel'] format_strawberryfield.deletetmpstorage_subscriber: class: Drupal\format_strawberryfield\EventSubscriber\formatStrawberryfieldDeleteTmpStorage tags: diff --git a/src/Entity/MetadataDisplayEntity.php b/src/Entity/MetadataDisplayEntity.php index de628033..286836d8 100644 --- a/src/Entity/MetadataDisplayEntity.php +++ b/src/Entity/MetadataDisplayEntity.php @@ -164,6 +164,16 @@ class MetadataDisplayEntity extends RevisionableContentEntityBase implements Met CONST ERRORED_CACHE_TAG_ID = 'format_strawberry:metadata_display_errored:'; + CONST ALLOWED_MIMETYPES = [ + 'text/html' => 'HTML', + 'application/json' => 'JSON', + 'application/ld+json' => 'JSON-LD', + 'application/xml' => 'XML', + 'text/text' => 'TEXT', + 'text/turtle' => 'RDF/TURTLE', + 'text/csv' => 'CSV', + ]; + /** * Calculated Twig vars used by this template. * @@ -397,15 +407,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { 'default_value' => 'text/html', 'max_length' => 64, 'cardinality' => 1, - 'allowed_values' => [ - 'text/html' => 'HTML', - 'application/json' => 'JSON', - 'application/ld+json' => 'JSON-LD', - 'application/xml' => 'XML', - 'text/text' => 'TEXT', - 'text/turtle' => 'RDF/TURTLE', - 'text/csv' => 'CSV', - ], + 'allowed_values' => static::ALLOWED_MIMETYPES, ]) ->setRequired(TRUE) ->setDisplayOptions('view', [ diff --git a/src/TwigExtension.php b/src/TwigExtension.php index c53243ac..5515d38d 100644 --- a/src/TwigExtension.php +++ b/src/TwigExtension.php @@ -4,9 +4,15 @@ use Drupal\Component\Utility\Html; use Drupal\search_api\Query\QueryInterface; +use Drupal\format_strawberryfield\Entity\MetadataDisplayEntity; use Drupal\search_api\SearchApiException; use Drupal\strawberryfield\Plugin\search_api\datasource\StrawberryfieldFlavorDatasource; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpKernel\HttpKernelInterface; use Twig\Extension\AbstractExtension; +use Drupal\Core\Url; use Twig\Markup; use Twig\TwigTest; use Twig\TwigFilter; @@ -38,17 +44,33 @@ class TwigExtension extends AbstractExtension { */ protected $renderer; + /** + * The request stack. + * + * @var \Symfony\Component\HttpFoundation\RequestStack + */ + protected $requestStack; + + /** + * @var HttpKernelInterface + */ + protected HttpKernelInterface $httpKernel; + /** * Constructs \Drupal\format_strawberryfield\TwigExtension * - * @param \Drupal\Core\Render\RendererInterface $renderer + * @param RendererInterface $renderer * The renderer. - * @param \Drupal\search_api\ParseMode\ParseModePluginManager $parse_mode_manager + * @param ParseModePluginManager $parse_mode_manager * The search API parse mode manager. + * @param RequestStack $request_stack + * @param HttpKernelInterface $http_kernel */ - public function __construct(RendererInterface $renderer, ParseModePluginManager $parse_mode_manager) { + public function __construct(RendererInterface $renderer, ParseModePluginManager $parse_mode_manager, RequestStack $request_stack, HttpKernelInterface $http_kernel) { $this->renderer = $renderer; $this->parseModeManager = $parse_mode_manager; + $this->requestStack = $request_stack; + $this->httpKernel = $http_kernel; } public function getTests(): array { @@ -80,6 +102,7 @@ public function getFunctions() { [$this, 'clipboardCopy']), new TwigFunction('sbf_search_api', [$this, 'searchApiQuery']), + new TwigFunction('sbf_file_content', [$this, 'sbfFileContent'], ['is_safe' => ['all']]), ]; } @@ -121,7 +144,7 @@ public function entityIdsByLabel( string $label, string $entity_type, string $bundle_identifier = NULL, - $limit = 1 + $limit = 1 ): ?array { $fields = [ 'node' => ['title', 'type'], @@ -583,4 +606,41 @@ public function searchApiQuery(string $index, string $term, array $fulltext, arr } return []; } + + public function sbfFileContent(string $node_uuid, string $file_uuid, string $format) { + $current_request = $this->requestStack->getCurrentRequest(); + $file_binary_url = Url::fromRoute('format_strawberryfield.binary', ['node' => $node_uuid, 'uuid' => $file_uuid, 'format' => $format ], []) + ->toString(TRUE) + ->getGeneratedUrl(); + + $request = Request::create($file_binary_url, 'GET', [], $current_request->cookies->all(), [], $current_request->server->all() + ); + if ($current_request->getSession()) { + $request->setSession($current_request->getSession()); + } + try { + $response = $this->httpKernel->handle($request, HttpKernelInterface::SUB_REQUEST); + } + catch (\Exception $e) { + return $e->getMessage(); + } + + if ($this->requestStack->getCurrentRequest() !== $current_request->getPathInfo()) { + $this->requestStack->pop(); + } + if ($response->isSuccessful() && $response instanceof BinaryFileResponse) { + /** @var \Symfony\Component\HttpFoundation\File\File $file */ + $file = $response->getFile(); + if ($file) { + // Only return Text values we allow also as output of a Twig Template + // This will at least stop users from trying to fetch images and is faster + // That preloading the File and validating it upfront for valid mimetypes? + if (isset(MetadataDisplayEntity::ALLOWED_MIMETYPES[$file->getMimeType()])) { + return $file->getContent(); + } + } + } + return ''; + } + } From ba9ca1986d6119fa4c3a2c91e3fbe533b016107a Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Thu, 14 Nov 2024 11:36:06 -0500 Subject: [PATCH 2/8] Adds timeout/delay if Views Change event listener has not yet started Basically keep doing that/delaying the event until (if ever) we have an event listener. Also attach the event listener only to the Body. We need it only once. Not more. --- format_strawberryfield.libraries.yml | 1 + js/iiif-archipelago-interactions_utils.js | 33 ++++++++++++++++--- .../js/sbf-views-ajax-interactions.js | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/format_strawberryfield.libraries.yml b/format_strawberryfield.libraries.yml index a3145ef1..9f1e1098 100644 --- a/format_strawberryfield.libraries.yml +++ b/format_strawberryfield.libraries.yml @@ -6,6 +6,7 @@ iiif_formatstrawberryfield_utils: dependencies: - core/jquery - core/drupal + - core/once - core/drupalSettings - format_strawberryfield/jmespath_strawberry - format_strawberryfield/svgpath_polyfull diff --git a/js/iiif-archipelago-interactions_utils.js b/js/iiif-archipelago-interactions_utils.js index efe09d05..5192101b 100644 --- a/js/iiif-archipelago-interactions_utils.js +++ b/js/iiif-archipelago-interactions_utils.js @@ -1,4 +1,4 @@ -(function ($, Drupal, drupalSettings, jmespath) { +(function ($, Drupal, drupalSettings, jmespath, once) { 'use strict'; var FormatStrawberryfieldIiifUtils = { @@ -44,7 +44,23 @@ nodeidsArray = nodeids } const event = new CustomEvent('sbf:ado:view:change', { bubbles: true, detail: {nodeid: nodeidsArray} }); - el.dispatchEvent(event); + // A view might/might not have yet attach itself to listen. + // We have no control on Behavior attachment order in Drupal + // And can also not make this library depend at all on sbf-views-ajax-interactions. + // But we can check if it is already attached but just using once() + // and if not, delay with a future timeout the dispatching in the hope it finds its way. + // Literally give it a second after sync code has run. + // See Drupal.behaviors.sbf_views_ajax_interactions + const viewEventListenerInit = once.filter('listen-ado-view-change', 'body') + if (!viewEventListenerInit?.length) { + setTimeout(() => { + el.dispatchEvent(event); + } + , 1000); + } + else { + el.dispatchEvent(event); + } return this; }, @@ -61,7 +77,16 @@ encodedImageAnnotationOne = encodedImageAnnotation } const event = new CustomEvent('sbf:ado:view:change', { bubbles: true, detail: {image_annotation: encodedImageAnnotationOne} }); - el.dispatchEvent(event); + const viewEventListenerInit = once.filter('listen-ado-view-change', 'body') + if (!viewEventListenerInit?.length) { + setTimeout(() => { + el.dispatchEvent(event); + } + , 1000); + } + else { + el.dispatchEvent(event); + } return this; }, @@ -262,4 +287,4 @@ /* Make it part of the Global Drupal Object */ Drupal.FormatStrawberryfieldIiifUtils = FormatStrawberryfieldIiifUtils; -})(jQuery, Drupal, drupalSettings, jmespath); +})(jQuery, Drupal, drupalSettings, jmespath, once); diff --git a/modules/format_strawberryfield_views/js/sbf-views-ajax-interactions.js b/modules/format_strawberryfield_views/js/sbf-views-ajax-interactions.js index 796cd77a..487e8c1c 100644 --- a/modules/format_strawberryfield_views/js/sbf-views-ajax-interactions.js +++ b/modules/format_strawberryfield_views/js/sbf-views-ajax-interactions.js @@ -53,7 +53,7 @@ Drupal.behaviors.sbf_views_ajax_interactions = { attach: function (context, settings) { - once('listen-ado-view-change', 'div.view', context).forEach(function (value, index) { + once('listen-ado-view-change', 'body').forEach(function (value, index) { console.log("initializing 'sbf:ado:view:change' event listener on ADO changes"); // Because this is a single Listener for all views that have this enabled // the actual caller id will be passed as part of the event data From 18b2f16a7c8cfe5396532f7089e27f60df630c0a Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Thu, 14 Nov 2024 13:13:24 -0500 Subject: [PATCH 3/8] Uses fragments for both pages/search Also updates them. Probably missing some "side" effects of this --- js/mirador_strawberry.js | 83 +++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/js/mirador_strawberry.js b/js/mirador_strawberry.js index eb5e7ce6..ed508992 100644 --- a/js/mirador_strawberry.js +++ b/js/mirador_strawberry.js @@ -194,7 +194,22 @@ } } - const newParams = Object.fromEntries(new URLSearchParams(location.search)) + const newParams = {}; + const urlArray = location.hash.replace('#','').split('/'); + const urlHash = {}; + // Because one action might not have the value for another action + // We will parse the params upfront from the hash. + for (let i = 0; i < urlArray.length; i += 2) { + urlHash[urlArray[i]] = urlArray[i + 1]; + } + if (urlHash['search'] != undefined) { + newParams.search = decodeURIComponent(urlHash['search'].replace(/\+/g, " ")); + } + if (urlHash['page'] != undefined) { + newParams.page = decodeURIComponent(urlHash['page'].replace(/\+/g, " ")); + } + + if ( action.type === ActionTypes.SET_CANVAS || action.type === ActionTypes.SET_WINDOW_VIEW_TYPE @@ -280,6 +295,14 @@ canvas => canvas['@id'] ); } + // Build page parameter + if (visibleCanvases?.length) { + const canvasIndices = visibleCanvases.map(c => canvasIds.indexOf(c) + 1) + if (canvasIndices.length == 1) { + newParams.page = canvasIndices[0] + } + } + // even if we have no search being triggered by interactions, we should fetch the // Now at the end. If a VTT annotation requested a Canvas to be set. we need to check if we have in the config // A temporary stored valued of the last clicked annotation. @@ -298,33 +321,21 @@ const { windowId, companionWindowId } = action const query = yield effects.select(Mirador.selectors.getSearchQuery, { companionWindowId, windowId }) newParams.search = query - let $fragment = ''; - for (const [p, val] of new URLSearchParams(newParams).entries()) { - $fragment += `${p}/${val}/`; - }; - $fragment = $fragment.slice(0, -1); - history.replaceState( - { searchParams: newParams }, - '', - `${window.location.pathname}#${$fragment}` - ); } else if (action.type === ActionTypes.REMOVE_SEARCH) { delete newParams.search - let $fragment = ''; - for (const [p, val] of new URLSearchParams(newParams).entries()) { - $fragment += `${p}/${val}/`; - }; - $fragment = $fragment.slice(0, -1); - history.replaceState( - { searchParams: newParams }, - '', - `${window.location.pathname}#${$fragment}` - ); } - - - + // Set the fragment, no matter what. + let $fragment = ''; + for (const [p, val] of new URLSearchParams(newParams).entries()) { + $fragment += `${p}/${val}/`; + }; + $fragment = $fragment.slice(0, -1); + history.replaceState( + { searchParams: newParams }, + '', + `${window.location.pathname}#${$fragment}` + ); } function* rootSaga() { yield effects.takeEvery( @@ -421,10 +432,31 @@ } }; + const readFragmentPage = function() { + const urlArray = window.location.hash.replace('#','').split('/'); + const urlHash = {}; + for (let i = 0; i < urlArray.length; i += 2) { + urlHash[urlArray[i]] = urlArray[i + 1]; + } + if (urlHash['page'] != undefined) { + return parseInt(decodeURIComponent(urlHash['page'].replace(/\+/g, " "))); + } + else { + return 0; + } + }; + const search_string = readFragmentSearch(); + const page_string = readFragmentPage(); if (search_string.length > 0 ) { $options.windows[0].defaultSearchQuery = search_string; } + // Note. if the setting "switchCanvasOnSearch": true is selected + // And there is a search + // And there is a hit, start canvas will have no effect. You are warned. + if (parseInt(page_string) > 0 ) { + $options.windows[0].canvasIndex = parseInt(page_string) - 1 ; + } // Allow last minute overrides. These are more complex bc we have windows as an array and window too. // Allow a last minute override, exclude main element manifest @@ -456,8 +488,7 @@ ...viewer_override, }; } - - + $options.state = {}; //@TODO add an extra Manifests key with every other one so people can select the others. if (drupalSettings.format_strawberryfield.mirador[element_id]['custom_js'] == true) { From aec2499db24b7cdcd2195bcbe30b98823c6d3b21 Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Fri, 15 Nov 2024 17:47:34 -0500 Subject: [PATCH 4/8] This can be better. But at least for this commit it won't generate render errors Next step is to make it "elegant" --- src/TwigExtension.php | 58 +++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/TwigExtension.php b/src/TwigExtension.php index 5515d38d..1ce9971b 100644 --- a/src/TwigExtension.php +++ b/src/TwigExtension.php @@ -3,6 +3,8 @@ namespace Drupal\format_strawberryfield; use Drupal\Component\Utility\Html; +use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\file\FileInterface; use Drupal\search_api\Query\QueryInterface; use Drupal\format_strawberryfield\Entity\MetadataDisplayEntity; use Drupal\search_api\SearchApiException; @@ -608,39 +610,37 @@ public function searchApiQuery(string $index, string $term, array $fulltext, arr } public function sbfFileContent(string $node_uuid, string $file_uuid, string $format) { - $current_request = $this->requestStack->getCurrentRequest(); - $file_binary_url = Url::fromRoute('format_strawberryfield.binary', ['node' => $node_uuid, 'uuid' => $file_uuid, 'format' => $format ], []) - ->toString(TRUE) - ->getGeneratedUrl(); - - $request = Request::create($file_binary_url, 'GET', [], $current_request->cookies->all(), [], $current_request->server->all() - ); - if ($current_request->getSession()) { - $request->setSession($current_request->getSession()); - } try { - $response = $this->httpKernel->handle($request, HttpKernelInterface::SUB_REQUEST); - } - catch (\Exception $e) { - return $e->getMessage(); - } - - if ($this->requestStack->getCurrentRequest() !== $current_request->getPathInfo()) { - $this->requestStack->pop(); - } - if ($response->isSuccessful() && $response instanceof BinaryFileResponse) { - /** @var \Symfony\Component\HttpFoundation\File\File $file */ - $file = $response->getFile(); - if ($file) { - // Only return Text values we allow also as output of a Twig Template - // This will at least stop users from trying to fetch images and is faster - // That preloading the File and validating it upfront for valid mimetypes? - if (isset(MetadataDisplayEntity::ALLOWED_MIMETYPES[$file->getMimeType()])) { - return $file->getContent(); + /** @var ContentEntityInterface[] $nodes */ + $nodes = \Drupal::entityTypeManager() + ->getStorage('node') + ->loadByProperties(['uuid' => $node_uuid]); + $node = reset($nodes); + + if ($node && $node->access('view') && $node->hasField('field_file_drop')) { + /** @var FileInterface[] $files */ + $files = \Drupal::entityTypeManager() + ->getStorage('file') + ->loadByProperties(['uuid' => $file_uuid]); + $file = reset($files); + $found = FALSE; + $files_referenced = $node->get('field_file_drop')->getValue(); + foreach ($files_referenced as $fileinfo) { + if ($fileinfo['target_id'] == $file->id()) { + /* @var $found \Drupal\file\Entity\File */ + $found = $file; + break; + } + } + if($found) { + return file_get_contents($file->getFileUri()); } } } + catch (\Exception $exception) { + + } + return ''; } - } From 6784b1010c7027cafe70ad5a49f2b7665fc6a584 Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Mon, 18 Nov 2024 09:48:56 -0500 Subject: [PATCH 5/8] don't forget to filter agains text types and JSON/JSON-LD only --- .../format_strawberryfield_facets.module | 0 src/TwigExtension.php | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 modules/format_strawberryfield_facets/format_strawberryfield_facets.module diff --git a/modules/format_strawberryfield_facets/format_strawberryfield_facets.module b/modules/format_strawberryfield_facets/format_strawberryfield_facets.module new file mode 100644 index 00000000..e69de29b diff --git a/src/TwigExtension.php b/src/TwigExtension.php index 1ce9971b..206c90db 100644 --- a/src/TwigExtension.php +++ b/src/TwigExtension.php @@ -632,13 +632,13 @@ public function sbfFileContent(string $node_uuid, string $file_uuid, string $for break; } } - if($found) { - return file_get_contents($file->getFileUri()); + if($found && isset(MetadataDisplayEntity::ALLOWED_MIMETYPES[$file->getMimeType()])) { + return file_get_contents($file->getFileUri()); } } } catch (\Exception $exception) { - + return ''; } return ''; From 27b42f37149620de34337f62380bca521c6a940c Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Mon, 2 Dec 2024 12:33:38 -0500 Subject: [PATCH 6/8] wrong mimetype! --- src/Entity/MetadataDisplayEntity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entity/MetadataDisplayEntity.php b/src/Entity/MetadataDisplayEntity.php index 286836d8..8396026d 100644 --- a/src/Entity/MetadataDisplayEntity.php +++ b/src/Entity/MetadataDisplayEntity.php @@ -169,7 +169,7 @@ class MetadataDisplayEntity extends RevisionableContentEntityBase implements Met 'application/json' => 'JSON', 'application/ld+json' => 'JSON-LD', 'application/xml' => 'XML', - 'text/text' => 'TEXT', + 'text/plain' => 'TEXT', 'text/turtle' => 'RDF/TURTLE', 'text/csv' => 'CSV', ]; From 2d0a690a09c8d5232d60c64059f1e49c6b7f315b Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Mon, 2 Dec 2024 12:46:59 -0500 Subject: [PATCH 7/8] Update hook for correct text/plain mimetype --- format_strawberryfield.install | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/format_strawberryfield.install b/format_strawberryfield.install index 21fd2821..f0fa530e 100644 --- a/format_strawberryfield.install +++ b/format_strawberryfield.install @@ -361,4 +361,24 @@ function format_strawberryfield_update_9001() { else { return 'Metadata API Configuration Entity already exists'; } -} \ No newline at end of file +} + + +/** + * Implements hook_update_N(). + * + * Updates Mimetypes for text/plain + * + */ +function format_strawberryfield_update_9002() { + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + $field_storage_definition = $definition_update_manager->getFieldStorageDefinition('mimetype', 'metadatadisplay_entity'); + $settings = $field_storage_definition->getSettings(); + $settings['allowed_values'] = \Drupal\format_strawberryfield\Entity\MetadataDisplayEntity::ALLOWED_MIMETYPES; + $field_storage_definition->setSettings($settings); + $definition_update_manager->updateFieldStorageDefinition($field_storage_definition); +} + + + + From 5b1fc7413c6405971c989bf66441f0792bc42494 Mon Sep 17 00:00:00 2001 From: Diego Pino Navarro Date: Mon, 2 Dec 2024 12:55:45 -0500 Subject: [PATCH 8/8] More legacy text/text --- format_strawberryfield.install | 2 +- src/Controller/MetadataAPIController.php | 4 ++-- src/Controller/MetadataExposeDisplayController.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/format_strawberryfield.install b/format_strawberryfield.install index f0fa530e..b4b17145 100644 --- a/format_strawberryfield.install +++ b/format_strawberryfield.install @@ -39,7 +39,7 @@ function format_strawberryfield_update_8001() { 'application/json' => 'JSON', 'application/ld+json' => 'JSON-LD', 'application/xml' => 'XML', - 'text/text' => 'TEXT', + 'text/plain' => 'TEXT', 'text/turtle' => 'RDF/TURTLE', 'text/csv' => 'CSV', ], diff --git a/src/Controller/MetadataAPIController.php b/src/Controller/MetadataAPIController.php index dfd8b07a..fd92f96e 100644 --- a/src/Controller/MetadataAPIController.php +++ b/src/Controller/MetadataAPIController.php @@ -702,7 +702,7 @@ function () use ($context_wrapper, $metadatadisplay_wrapper_entity break; case 'application/xml': - case 'text/text': + case 'text/plain': case 'text/turtle': case 'text/html': case 'text/csv': @@ -759,7 +759,7 @@ function () use ($context_wrapper, $metadatadisplay_wrapper_entity break; case 'application/xml': - case 'text/text': + case 'text/plain': case 'text/turtle': case 'text/html': case 'text/csv': diff --git a/src/Controller/MetadataExposeDisplayController.php b/src/Controller/MetadataExposeDisplayController.php index 8d2d8e49..e7ef6caf 100644 --- a/src/Controller/MetadataExposeDisplayController.php +++ b/src/Controller/MetadataExposeDisplayController.php @@ -297,7 +297,7 @@ function () use ($context, $original_context, $metadatadisplay_entity) { break; case 'application/xml': - case 'text/text': + case 'text/plain': case 'text/turtle': case 'text/html': case 'text/csv':