Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 118 additions & 110 deletions src/Plugin/Field/FieldFormatter/StrawberryMediaFormatter.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Created by PhpStorm.
* User: dpino
Expand All @@ -16,6 +17,7 @@
use Drupal\Core\StreamWrapper\StreamWrapperManager;
use Drupal\format_strawberryfield\Controller\WebAnnotationController;
use Drupal\Core\Url;

/**
* Simplistic Strawberry Field formatter.
*
Expand All @@ -32,6 +34,7 @@
* )
*/
class StrawberryMediaFormatter extends StrawberryBaseFormatter {

/**
* {@inheritdoc}
*/
Expand All @@ -46,74 +49,75 @@ public static function defaultSettings() {
'thumbnails' => TRUE,
];
}

/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
//@TODO document that 2 base urls are just needed when developing (localhost syndrom)
return [
'iiif_group' => [
'#type' => 'checkbox',
'#title' => t('Group all Media files in a single viewer?'),
'#default_value' => $this->getSetting('iiif_group'),
'iiif_group' => [
'#type' => 'checkbox',
'#title' => t('Group all Media files in a single viewer?'),
'#default_value' => $this->getSetting('iiif_group'),
],
'thumbnails' => [
'#type' => 'checkbox',
'#title' => t('Show a thumbnail reference bar.'),
'#default_value' => $this->getSetting('thumbnails'),
],
'webannotations' => [
'#type' => 'checkbox',
'#title' => t('Enable loading/editing of W3C webAnnotations.'),
'#description' => t('<a href="https://www.w3.org/TR/annotation-model/#index-of-json-keys">Click here</a> To learn more about the JSON format of a Web Annotation'),
'#default_value' => $this->getSetting('webannotations'),
'#attributes' => [
'data-formatter-selector' => 'webannotations',
],
'thumbnails' => [
'#type' => 'checkbox',
'#title' => t('Show a thumbnail reference bar.'),
'#default_value' => $this->getSetting('thumbnails'),
],
'webannotations_tool' => [
'#type' => 'select',
'#options' => [
'rect' => 'Rectangle',
'polygon' => 'Polygon',
],
'webannotations' => [
'#type' => 'checkbox',
'#title' => t('Enable loading/editing of W3C webAnnotations.'),
'#description' => t('<a href="https://www.w3.org/TR/annotation-model/#index-of-json-keys">Click here</a> To learn more about the JSON format of a Web Annotation'),
'#default_value' => $this->getSetting('webannotations'),
'#attributes' => [
'data-formatter-selector' => 'webannotations',
'#title' => t('What tool to enable'),
'#description' => t('This defines if the user will be able to use the Polygon or the Rectangle Tool'),
'#default_value' => $this->getSetting('webannotations_tool'),
'#states' => [
'visible' => [
':input[data-formatter-selector="webannotations"]' => ['checked' => TRUE],
],
],
'webannotations_tool' => [
'#type' => 'select',
'#options' => [
'rect' => 'Rectangle',
'polygon' => 'Polygon'
],
'#title' => t('What tool to enable'),
'#description' => t('This defines if the user will be able to use the Polygon or the Rectangle Tool'),
'#default_value' => $this->getSetting('webannotations_tool'),
'#states' => [
'visible' => [
':input[data-formatter-selector="webannotations"]' => ['checked' => TRUE],
],
]
],
'json_key_source' => [
'#type' => 'textfield',
'#title' => t('JSON Key from where to fetch Media URLs'),
'#default_value' => $this->getSetting('json_key_source'),
'#required' => TRUE
],
'max_width' => [
'#type' => 'number',
'#title' => $this->t('Maximum width'),
'#description' => $this->t('Use 0 to force 100% width'),
'#default_value' => $this->getSetting('max_width'),
'#size' => 5,
'#maxlength' => 5,
'#field_suffix' => $this->t('pixels'),
'#min' => 0,
'#required' => TRUE
],
'max_height' => [
'#type' => 'number',
'#title' => $this->t('Maximum height'),
'#default_value' => $this->getSetting('max_height'),
'#size' => 5,
'#maxlength' => 5,
'#field_suffix' => $this->t('pixels'),
'#min' => 0,
'#required' => TRUE
],
] + parent::settingsForm($form, $form_state);
],
'json_key_source' => [
'#type' => 'textfield',
'#title' => t('JSON Key from where to fetch Media URLs'),
'#default_value' => $this->getSetting('json_key_source'),
'#required' => TRUE,
],
'max_width' => [
'#type' => 'number',
'#title' => $this->t('Maximum width'),
'#description' => $this->t('Use 0 to force 100% width'),
'#default_value' => $this->getSetting('max_width'),
'#size' => 5,
'#maxlength' => 5,
'#field_suffix' => $this->t('pixels'),
'#min' => 0,
'#required' => TRUE,
],
'max_height' => [
'#type' => 'number',
'#title' => $this->t('Maximum height'),
'#default_value' => $this->getSetting('max_height'),
'#size' => 5,
'#maxlength' => 5,
'#field_suffix' => $this->t('pixels'),
'#min' => 0,
'#required' => TRUE,
],
] + parent::settingsForm($form, $form_state);
}

/**
Expand Down Expand Up @@ -151,30 +155,27 @@ public function settingsSummary() {
]
);


return $summary;
}


/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = [];
$max_width = $this->getSetting('max_width');
$max_width_css = empty($max_width) || $max_width == 0 ? '100%' : $max_width .'px';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep. what a shame! sloppy iterative code. Thanks!

$max_width_css = empty($max_width) ? '100%' : $max_width . 'px';
$max_height = $this->getSetting('max_height');
$grouped = $this->getSetting('iiif_group');
$thumbnails = $this->getSetting('thumbnails');
$webannotations = $this->getSetting('webannotations');
$webannotations_tool = $this->getSetting('webannotations_tool');

/* @var \Drupal\file\FileInterface[] $files */
// Fixing the key to extract while coding to 'Media'
// Fixing the key to extract while coding to 'Media'.
$key = $this->getSetting('json_key_source');

$nodeuuid = $items->getEntity()->uuid();
$nodeid = $items->getEntity()->id();
$fieldname = $items->getName();

foreach ($items as $delta => $item) {
Expand Down Expand Up @@ -206,7 +207,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
$elements[$delta]['#attached']['library'][] = 'format_strawberryfield/iiif_openseadragon_strawberry';

if (isset($jsondata[$key])) {
// Order Images based on a given 'sequence' key
// Order Images based on a given 'sequence' key.
$ordersubkey = 'sequence';
StrawberryfieldJsonHelper::orderSequence($jsondata, $key, $ordersubkey);
$iiifhelper = new IiifHelper($this->getIiifUrls()['public'], $this->getIiifUrls()['internal']);
Expand All @@ -215,97 +216,103 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
if (isset($mediaitem['type']) && $mediaitem['type'] == 'Image') {
if (isset($mediaitem['dr:fid'])) {
// @TODO check if loading the entity is really needed to check access.
$file = OcflHelper::resolvetoFIDtoURI(
$mediaitem['dr:fid']
);
$file = OcflHelper::resolvetoFIDtoURI($mediaitem['dr:fid']);

//@TODO if no media key to file loading was possible
// means we have a broken/missing media reference
// we should inform to logs and continue
//@TODO if no media key to file loading was possible means we have
// a broken/missing media reference we should inform to logs and
// continue.
if (!$file) {
continue;

}
if ($this->checkAccess($file)) {
$iiifidentifier = urlencode(
StreamWrapperManager::getTarget($file->getFileUri())
);
$iiifidentifier = urlencode(StreamWrapperManager::getTarget($file->getFileUri()));
if ($iiifidentifier == NULL || empty($iiifidentifier)) {
continue;
}
// ImageToolKit use the $file->getFileUri(), we don't want that yet
// ImageToolKit use the $file->getFileUri(), we don't want that
// yet.
// @see https://github.com/esmero/format_strawberry/issues/1

//@ TODO recheck cache tags here, since we are not really using the file itself.
$filecachetags = $file->getCacheTags();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonder if we should add the file cache tags instead of removing this? (Given its and not Solved @TODO) or do you think it is not needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aw sorry about that, we're not doing anything with the tags so maybe some more work is needed for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. Let's keep the //@todo for now and remove 240. We can work on that in another issue. Thanks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey. I will merge this. We can deal with the @todo another day. I have done the cache stuff on the WARC formatter so we can copy from there. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the cache tags to the element delta, is that what would be intended?

$iiifpublicinfojson = $iiifhelper->getPublicInfoJson($iiifidentifier);

$groupid = 'iiif-'.$items->getName(
).'-'.$nodeuuid.'-'.$delta.'-media';
$uniqueid = $groupid.$i;
$groupid = 'iiif-' . $items->getName() . '-' . $nodeuuid . '-' . $delta . '-media';
$uniqueid = $groupid . $i;

$elements[$delta]['media'.$i] = [
$elements[$delta]['media' . $i] = [
'#type' => 'container',
'#default_value' => $uniqueid,
'#attributes' => [
'id' => $uniqueid,
'class' => ['strawberry-media-item','field-iiif','container'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this the actual fix! Good. Good.

'class' => [
'strawberry-media-item',
'field-iiif',
],
'data-iiif-infojson' => $iiifpublicinfojson,
'data-iiif-group' => $grouped ? $groupid : $uniqueid,
'data-iiif-thumbnails' => $thumbnails,
'style' => "width:{$max_width_css}; height:{$max_height}px",
],
//@ TODO recheck cache tags here, since we are not really using
// the file itself.
'#cache' => [
'tags' => $file->getCacheTags(),
],
];
if (isset($item->_attributes)) {
$elements[$delta] += ['#attributes' => []];
$elements[$delta]['#attributes'] += $item->_attributes;
// Unset field item attributes since they have been included in the
// formatter output and should not be rendered in the field template.
// Unset field item attributes since they have been included
// in the formatter output and should not be rendered in the
// field template.
unset($item->_attributes);
}
// @TODO deal with a lot of Media single strawberryfield
// Idea would be to allow a setting that says, A) all same viewer(aggregate)
// Idea would be to allow a setting that says, A) all same
// viewer(aggregate)
// B) individual viewers for each?
// C) only first one?
// We will assign a group based on the UUID of the node containing this
// to idenfity all the divs that we will create. And only first one will be the container in case of many?
// so a jquery selector that uses that group as filter for a search.
// Drupal JS settings get accumulated. So in a single search results site we will have for each
// Formatter one passed. Reason we use 'innode' array key using our $uniqueid
// We will assign a group based on the UUID of the node
// containing this to idenfity all the divs that we will create.
// And only first one will be the container in case of many? so
// a jquery selector that uses that group as filter for a
// search.
// Drupal JS settings get accumulated. So in a single search
// results site we will have for each Formatter one passed.
// Reason we use 'innode' array key using our $uniqueid
// @TODO probably better to use uuid() or the node id() instead of $uniqueid
$elements[$delta]['media'.$i]['#attributes']['data-iiif-infojson'] = $iiifpublicinfojson;
$elements[$delta]['media'.$i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon']['innode'][$uniqueid] = $nodeuuid;
$elements[$delta]['media'.$i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['width'] = $max_width_css;
$elements[$delta]['media'.$i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['dr:uuid'] = $file->uuid();
$elements[$delta]['media' . $i]['#attributes']['data-iiif-infojson'] = $iiifpublicinfojson;
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon']['innode'][$uniqueid] = $nodeuuid;
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['width'] = $max_width_css;
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['dr:uuid'] = $file->uuid();
// Used to keep annotations around during edit.
// Note: Since View modes are cached, if no change to the NODE this will be served from a cache! mmm.
// Note: Since View modes are cached, if no change to the NODE
// this will be served from a cache! mmm.
if ($this->currentUser->hasPermission('view strawberryfield webannotation') && $webannotations) {
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['keystoreid'] = WebAnnotationController::getTempStoreKeyName($fieldname, $delta, $nodeuuid);
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['webannotations'] = (boolean) $webannotations;
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['webannotations_tool'] = $webannotations_tool ? $webannotations_tool : 'rect';
// This also never runs if cached. So after deletion we better call the controller!
// This also never runs if cached. So after deletion we better
// call the controller!
if (!empty($jsondata['ap:annotationCollection']) && is_array($jsondata['ap:annotationCollection'])) {
$keystoreid = $elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['keystoreid'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This here seems to be a bug/of mine
WebAnnotationController::primeKeyStore() should be primed with the $keystoreid. Issue was this whole thing is cached and gets actually never call again after a cache clear. So wondering if it can be removed totally OR, better not and we need to prime it, at least once to avoid problems when the cache expires (e.g because of Node edit).

Can you please change to to WebAnnotationController::primeKeyStore($keystoreid) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost! Sorry again (what a day!) its not $elements[$delta] its $items[$delta], $elements[$delta] its an render array, $items[$delta] the actual field with JSON data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops sorry about that!

WebAnnotationController::primeKeyStore($items[$delta]);
WebAnnotationController::primeKeyStore($items[$delta], $keystoreid);
}
}
if ($this->currentUser) {
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['user']['url'] = Url::fromRoute('entity.user.canonical', ['user' => $this->currentUser->getAccount()->id()])->toString();
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['user']['url'] = Url::fromRoute('entity.user.canonical', ['user' => $this->currentUser->getAccount()->id()])->toString();
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['user']['name'] = $this->currentUser->getAccount()->getAccountName();
} else {
}
else {
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['user']['url'] = null;
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['user']['name'] = 'anonymous';
}


$elements[$delta]['media'.$i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['height'] = max(
$max_height,
480
);
$elements[$delta]['media' . $i]['#attached']['drupalSettings']['format_strawberryfield']['openseadragon'][$uniqueid]['height'] = max($max_height, 480);
}
} elseif (isset($mediaitem['url'])) {
$elements[$delta]['media'.$i] = [
'#markup' => 'Non managed '.$mediaitem['url'],
}
elseif (isset($mediaitem['url'])) {
$elements[$delta]['media' . $i] = [
'#markup' => 'Non managed ' . $mediaitem['url'],
'#prefix' => '<pre>',
'#suffix' => '</pre>',
];
Expand All @@ -315,14 +322,15 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
}
}
else {
$elements[$delta] = ['#markup' => $this->t('This Object has no Media')];
$elements[$delta] = ['#markup' => $this->t('This Object has no Media')];
}
// Get rid of empty #attributes key to avoid render error
if (isset( $elements[$delta]["#attributes"]) && empty( $elements[$delta]["#attributes"])) {
// Get rid of empty #attributes key to avoid render error.
if (isset($elements[$delta]["#attributes"]) && empty($elements[$delta]["#attributes"])) {
unset($elements[$delta]["#attributes"]);
}
}

return $elements;
}

}