Issue #1174892 by chr.fritsch, travist, Dave Reid, keithm, webchick, phenaproxima, Everett Zufelt, slashrsm, Wim Leers, RobW, seanB, xjm, Gábor Hojtsy, larowlan, ericduran, webflo, Berdir, pschuelke: File field formatters for rich media display with <video> and <audio> HTML5 elements
parent
f7c9dd9352
commit
8f300f534f
|
|
@ -70,6 +70,41 @@ field.field_settings.file:
|
|||
type: boolean
|
||||
label: 'Enable Description field'
|
||||
|
||||
file.formatter.media:
|
||||
type: mapping
|
||||
label: 'Media display format settings'
|
||||
mapping:
|
||||
controls:
|
||||
type: boolean
|
||||
label: 'Show playback controls'
|
||||
autoplay:
|
||||
type: boolean
|
||||
label: 'Autoplay'
|
||||
loop:
|
||||
type: boolean
|
||||
label: 'Loop'
|
||||
multiple_file_display_type:
|
||||
type: string
|
||||
label: 'Display of multiple files'
|
||||
|
||||
field.formatter.settings.file_audio:
|
||||
type: file.formatter.media
|
||||
label: 'Audio file display format settings'
|
||||
|
||||
field.formatter.settings.file_video:
|
||||
type: file.formatter.media
|
||||
label: 'Video file display format settings'
|
||||
mapping:
|
||||
muted:
|
||||
type: boolean
|
||||
label: 'Muted'
|
||||
width:
|
||||
type: integer
|
||||
label: 'Width'
|
||||
height:
|
||||
type: integer
|
||||
label: 'Height'
|
||||
|
||||
field.formatter.settings.file_default:
|
||||
type: mapping
|
||||
label: 'Generic file format settings'
|
||||
|
|
|
|||
|
|
@ -571,6 +571,12 @@ function file_theme() {
|
|||
'file_managed_file' => [
|
||||
'render element' => 'element',
|
||||
],
|
||||
'file_audio' => [
|
||||
'variables' => ['files' => [], 'attributes' => NULL],
|
||||
],
|
||||
'file_video' => [
|
||||
'variables' => ['files' => [], 'attributes' => NULL],
|
||||
],
|
||||
|
||||
// From file.field.inc.
|
||||
'file_widget_multiple' => [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\file\Plugin\Field\FieldFormatter;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'file_audio' formatter.
|
||||
*
|
||||
* @FieldFormatter(
|
||||
* id = "file_audio",
|
||||
* label = @Translation("Audio"),
|
||||
* description = @Translation("Display the file using an HTML5 audio tag."),
|
||||
* field_types = {
|
||||
* "file"
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class FileAudioFormatter extends FileMediaFormatterBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getMediaType() {
|
||||
return 'audio';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\file\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Template\Attribute;
|
||||
|
||||
/**
|
||||
* Base class for media file formatter.
|
||||
*/
|
||||
abstract class FileMediaFormatterBase extends FileFormatterBase implements FileMediaFormatterInterface {
|
||||
|
||||
/**
|
||||
* Gets the HTML tag for the formatter.
|
||||
*
|
||||
* @return string
|
||||
* The HTML tag of this formatter.
|
||||
*/
|
||||
protected function getHtmlTag() {
|
||||
return static::getMediaType();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function defaultSettings() {
|
||||
return [
|
||||
'controls' => TRUE,
|
||||
'autoplay' => FALSE,
|
||||
'loop' => FALSE,
|
||||
'multiple_file_display_type' => 'tags',
|
||||
] + parent::defaultSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state) {
|
||||
return [
|
||||
'controls' => [
|
||||
'#title' => $this->t('Show playback controls'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->getSetting('controls'),
|
||||
],
|
||||
'autoplay' => [
|
||||
'#title' => $this->t('Autoplay'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->getSetting('autoplay'),
|
||||
],
|
||||
'loop' => [
|
||||
'#title' => $this->t('Loop'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->getSetting('loop'),
|
||||
],
|
||||
'multiple_file_display_type' => [
|
||||
'#title' => $this->t('Display of multiple files'),
|
||||
'#type' => 'radios',
|
||||
'#options' => [
|
||||
'tags' => $this->t('Use multiple @tag tags, each with a single source.', ['@tag' => '<' . $this->getHtmlTag() . '>']),
|
||||
'sources' => $this->t('Use multiple sources within a single @tag tag.', ['@tag' => '<' . $this->getHtmlTag() . '>']),
|
||||
],
|
||||
'#default_value' => $this->getSetting('multiple_file_display_type'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function isApplicable(FieldDefinitionInterface $field_definition) {
|
||||
if (!parent::isApplicable($field_definition)) {
|
||||
return FALSE;
|
||||
}
|
||||
/** @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $extension_mime_type_guesser */
|
||||
$extension_mime_type_guesser = \Drupal::service('file.mime_type.guesser.extension');
|
||||
$extension_list = array_filter(preg_split('/\s+/', $field_definition->getSetting('file_extensions')));
|
||||
|
||||
foreach ($extension_list as $extension) {
|
||||
$mime_type = $extension_mime_type_guesser->guess('fakedFile.' . $extension);
|
||||
|
||||
if (static::mimeTypeApplies($mime_type)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsSummary() {
|
||||
$summary = [];
|
||||
$summary[] = $this->t('Playback controls: %controls', ['%controls' => $this->getSetting('controls') ? $this->t('visible') : $this->t('hidden')]);
|
||||
$summary[] = $this->t('Autoplay: %autoplay', ['%autoplay' => $this->getSetting('autoplay') ? $this->t('yes') : $this->t('no')]);
|
||||
$summary[] = $this->t('Loop: %loop', ['%loop' => $this->getSetting('loop') ? $this->t('yes') : $this->t('no')]);
|
||||
switch ($this->getSetting('multiple_file_display_type')) {
|
||||
case 'tags':
|
||||
$summary[] = $this->t('Multiple file display: Multiple HTML tags');
|
||||
break;
|
||||
|
||||
case 'sources':
|
||||
$summary[] = $this->t('Multiple file display: One HTML tag with multiple sources');
|
||||
break;
|
||||
}
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items, $langcode) {
|
||||
$elements = [];
|
||||
|
||||
$source_files = $this->getSourceFiles($items, $langcode);
|
||||
if (empty($source_files)) {
|
||||
return $elements;
|
||||
}
|
||||
|
||||
$attributes = $this->prepareAttributes();
|
||||
foreach ($source_files as $delta => $files) {
|
||||
$elements[$delta] = [
|
||||
'#theme' => $this->getPluginId(),
|
||||
'#attributes' => $attributes,
|
||||
'#files' => $files,
|
||||
'#cache' => ['tags' => []],
|
||||
];
|
||||
|
||||
$cache_tags = [];
|
||||
foreach ($files as $file) {
|
||||
$cache_tags = Cache::mergeTags($cache_tags, $file['file']->getCacheTags());
|
||||
}
|
||||
$elements[$delta]['#cache']['tags'] = $cache_tags;
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the attributes according to the settings.
|
||||
*
|
||||
* @param string[] $additional_attributes
|
||||
* Additional attributes to be applied to the HTML element. Attribute names
|
||||
* will be used as key and value in the HTML element.
|
||||
*
|
||||
* @return \Drupal\Core\Template\Attribute
|
||||
* Container with all the attributes for the HTML tag.
|
||||
*/
|
||||
protected function prepareAttributes(array $additional_attributes = []) {
|
||||
$attributes = new Attribute();
|
||||
foreach (['controls', 'autoplay', 'loop'] + $additional_attributes as $attribute) {
|
||||
if ($this->getSetting($attribute)) {
|
||||
$attributes->setAttribute($attribute, $attribute);
|
||||
}
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given MIME type applies to the media type of the formatter.
|
||||
*
|
||||
* @param string $mime_type
|
||||
* The complete MIME type.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the MIME type applies, FALSE otherwise.
|
||||
*/
|
||||
protected static function mimeTypeApplies($mime_type) {
|
||||
list($type) = explode('/', $mime_type, 2);
|
||||
return $type === static::getMediaType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets source files with attributes.
|
||||
*
|
||||
* @param \Drupal\Core\Field\EntityReferenceFieldItemListInterface $items
|
||||
* The item list.
|
||||
* @param string $langcode
|
||||
* The language code of the referenced entities to display.
|
||||
*
|
||||
* @return array
|
||||
* Numerically indexed array, which again contains an associative array with
|
||||
* the following key/values:
|
||||
* - file => \Drupal\file\Entity\File
|
||||
* - source_attributes => \Drupal\Core\Template\Attribute
|
||||
*/
|
||||
protected function getSourceFiles(EntityReferenceFieldItemListInterface $items, $langcode) {
|
||||
$source_files = [];
|
||||
// Because we can have the files grouped in a single media tag, we do a
|
||||
// grouping in case the multiple file behavior is not 'tags'.
|
||||
/** @var \Drupal\file\Entity\File $file */
|
||||
foreach ($this->getEntitiesToView($items, $langcode) as $file) {
|
||||
if (static::mimeTypeApplies($file->getMimeType())) {
|
||||
$source_attributes = new Attribute();
|
||||
$source_attributes
|
||||
->setAttribute('src', file_url_transform_relative(file_create_url($file->getFileUri())))
|
||||
->setAttribute('type', $file->getMimeType());
|
||||
if ($this->getSetting('multiple_file_display_type') === 'tags') {
|
||||
$source_files[] = [
|
||||
[
|
||||
'file' => $file,
|
||||
'source_attributes' => $source_attributes,
|
||||
],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$source_files[0][] = [
|
||||
'file' => $file,
|
||||
'source_attributes' => $source_attributes,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $source_files;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\file\Plugin\Field\FieldFormatter;
|
||||
|
||||
/**
|
||||
* Defines getter methods for FileMediaFormatterBase.
|
||||
*
|
||||
* This interface is used on the FileMediaFormatterBase class to ensure that
|
||||
* each file media formatter will be based on a media type.
|
||||
*
|
||||
* Abstract classes are not able to implement abstract static methods,
|
||||
* this interface will work around that.
|
||||
*
|
||||
* @see \Drupal\file\Plugin\Field\FieldFormatter\FileMediaFormatterBase
|
||||
*/
|
||||
interface FileMediaFormatterInterface {
|
||||
|
||||
/**
|
||||
* Gets the applicable media type for a formatter.
|
||||
*
|
||||
* @return string
|
||||
* The media type of this formatter.
|
||||
*/
|
||||
public static function getMediaType();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\file\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'file_video' formatter.
|
||||
*
|
||||
* @FieldFormatter(
|
||||
* id = "file_video",
|
||||
* label = @Translation("Video"),
|
||||
* description = @Translation("Display the file using an HTML5 video tag."),
|
||||
* field_types = {
|
||||
* "file"
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class FileVideoFormatter extends FileMediaFormatterBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getMediaType() {
|
||||
return 'video';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function defaultSettings() {
|
||||
return [
|
||||
'muted' => FALSE,
|
||||
'width' => 640,
|
||||
'height' => 480,
|
||||
] + parent::defaultSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state) {
|
||||
return parent::settingsForm($form, $form_state) + [
|
||||
'muted' => [
|
||||
'#title' => $this->t('Muted'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->getSetting('muted'),
|
||||
],
|
||||
'width' => [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Width'),
|
||||
'#default_value' => $this->getSetting('width'),
|
||||
'#size' => 5,
|
||||
'#maxlength' => 5,
|
||||
'#field_suffix' => $this->t('pixels'),
|
||||
'#min' => 0,
|
||||
'#required' => TRUE,
|
||||
],
|
||||
'height' => [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Height'),
|
||||
'#default_value' => $this->getSetting('height'),
|
||||
'#size' => 5,
|
||||
'#maxlength' => 5,
|
||||
'#field_suffix' => $this->t('pixels'),
|
||||
'#min' => 0,
|
||||
'#required' => TRUE,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsSummary() {
|
||||
$summary = parent::settingsSummary();
|
||||
$summary[] = $this->t('Muted: %muted', ['%muted' => $this->getSetting('muted') ? $this->t('yes') : $this->t('no')]);
|
||||
$summary[] = $this->t('Size: %width x %height pixels', [
|
||||
'%width' => $this->getSetting('width'),
|
||||
'%height' => $this->getSetting('height'),
|
||||
]);
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareAttributes(array $additional_attributes = []) {
|
||||
return parent::prepareAttributes(['muted'])
|
||||
->setAttribute('width', $this->getSetting('width'))
|
||||
->setAttribute('height', $this->getSetting('height'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display the file entity as an audio tag.
|
||||
*
|
||||
* Available variables:
|
||||
* - attributes: An array of HTML attributes, intended to be added to the
|
||||
* audio tag.
|
||||
* - files: And array of files to be added as sources for the audio tag. Each
|
||||
* element is an array with the following elements:
|
||||
* - file: The full file object.
|
||||
* - source_attributes: An array of HTML attributes for to be added to the
|
||||
* source tag.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
<audio {{ attributes }}>
|
||||
{% for file in files %}
|
||||
<source {{ file.source_attributes }} />
|
||||
{% endfor %}
|
||||
</audio>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display the file entity as a video tag.
|
||||
*
|
||||
* Available variables:
|
||||
* - attributes: An array of HTML attributes, intended to be added to the
|
||||
* video tag.
|
||||
* - files: And array of files to be added as sources for the video tag. Each
|
||||
* element is an array with the following elements:
|
||||
* - file: The full file object.
|
||||
* - source_attributes: An array of HTML attributes for to be added to the
|
||||
* source tag.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
<video {{ attributes }}>
|
||||
{% for file in files %}
|
||||
<source {{ file.source_attributes }} />
|
||||
{% endfor %}
|
||||
</video>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\file\Functional\Formatter;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\file\Entity\File;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\file\Plugin\Field\FieldFormatter\FileAudioFormatter
|
||||
* @group file
|
||||
*/
|
||||
class FileAudioFormatterTest extends FileMediaFormatterTestBase {
|
||||
|
||||
/**
|
||||
* @covers ::viewElements
|
||||
*
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
public function testRender($tag_count, $formatter_settings) {
|
||||
$field_config = $this->createMediaField('file_audio', 'mp3', $formatter_settings);
|
||||
|
||||
file_put_contents('public://file.mp3', str_repeat('t', 10));
|
||||
$file1 = File::create([
|
||||
'uri' => 'public://file.mp3',
|
||||
'filename' => 'file.mp3',
|
||||
]);
|
||||
$file1->save();
|
||||
|
||||
$file2 = File::create([
|
||||
'uri' => 'public://file.mp3',
|
||||
'filename' => 'file.mp3',
|
||||
]);
|
||||
$file2->save();
|
||||
|
||||
$entity = EntityTest::create([
|
||||
$field_config->getName() => [
|
||||
[
|
||||
'target_id' => $file1->id(),
|
||||
],
|
||||
[
|
||||
'target_id' => $file2->id(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
$entity->save();
|
||||
|
||||
$this->drupalGet($entity->toUrl());
|
||||
|
||||
$file1_url = file_url_transform_relative(file_create_url($file1->getFileUri()));
|
||||
$file2_url = file_url_transform_relative(file_create_url($file2->getFileUri()));
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
$assert_session->elementsCount('css', 'audio[controls="controls"]', $tag_count);
|
||||
$assert_session->elementExists('css', "audio > source[src='$file1_url'][type='audio/mpeg']");
|
||||
$assert_session->elementExists('css', "audio > source[src='$file2_url'][type='audio/mpeg']");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\file\Functional\Formatter;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Provides methods specifically for testing File module's media formatter's.
|
||||
*/
|
||||
abstract class FileMediaFormatterTestBase extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'entity_test',
|
||||
'field',
|
||||
'file',
|
||||
'user',
|
||||
'system',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->drupalCreateUser(['view test entity']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file field and set's the correct formatter.
|
||||
*
|
||||
* @param string $formatter
|
||||
* The formatter ID.
|
||||
* @param string $file_extensions
|
||||
* The file extensions of the new field.
|
||||
* @param array $formatter_settings
|
||||
* Settings for the formatter.
|
||||
*
|
||||
* @return \Drupal\field\Entity\FieldConfig
|
||||
* Newly created file field.
|
||||
*/
|
||||
protected function createMediaField($formatter, $file_extensions, array $formatter_settings = []) {
|
||||
$entity_type = $bundle = 'entity_test';
|
||||
$field_name = Unicode::strtolower($this->randomMachineName());
|
||||
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => $entity_type,
|
||||
'field_name' => $field_name,
|
||||
'type' => 'file',
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
])->save();
|
||||
$field_config = FieldConfig::create([
|
||||
'entity_type' => $entity_type,
|
||||
'field_name' => $field_name,
|
||||
'bundle' => $bundle,
|
||||
'settings' => [
|
||||
'file_extensions' => trim($file_extensions),
|
||||
],
|
||||
]);
|
||||
$field_config->save();
|
||||
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'full');
|
||||
$display->setComponent($field_name, [
|
||||
'type' => $formatter,
|
||||
'settings' => $formatter_settings,
|
||||
])->save();
|
||||
|
||||
return $field_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testRender.
|
||||
*
|
||||
* @return array
|
||||
* An array of data arrays.
|
||||
* The data array contains:
|
||||
* - The number of expected HTML tags.
|
||||
* - An array of settings for the field formatter.
|
||||
*/
|
||||
public function dataProvider() {
|
||||
return [
|
||||
[2, []],
|
||||
[1, ['multiple_file_display_type' => 'sources']],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\file\Functional\Formatter;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\file\Entity\File;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\file\Plugin\Field\FieldFormatter\FileVideoFormatter
|
||||
* @group file
|
||||
*/
|
||||
class FileVideoFormatterTest extends FileMediaFormatterTestBase {
|
||||
|
||||
/**
|
||||
* @covers ::viewElements
|
||||
*
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
public function testRender($tag_count, $formatter_settings) {
|
||||
$field_config = $this->createMediaField('file_video', 'mp4', $formatter_settings);
|
||||
|
||||
file_put_contents('public://file.mp4', str_repeat('t', 10));
|
||||
$file1 = File::create([
|
||||
'uri' => 'public://file.mp4',
|
||||
'filename' => 'file.mp4',
|
||||
]);
|
||||
$file1->save();
|
||||
|
||||
$file2 = File::create([
|
||||
'uri' => 'public://file.mp4',
|
||||
'filename' => 'file.mp4',
|
||||
]);
|
||||
$file2->save();
|
||||
|
||||
$entity = EntityTest::create([
|
||||
$field_config->getName() => [
|
||||
[
|
||||
'target_id' => $file1->id(),
|
||||
],
|
||||
[
|
||||
'target_id' => $file2->id(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
$entity->save();
|
||||
|
||||
$this->drupalGet($entity->toUrl());
|
||||
|
||||
$file1_url = file_url_transform_relative(file_create_url($file1->getFileUri()));
|
||||
$file2_url = file_url_transform_relative(file_create_url($file2->getFileUri()));
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
$assert_session->elementsCount('css', 'video[controls="controls"]', $tag_count);
|
||||
$assert_session->elementExists('css', "video > source[src='$file1_url'][type='video/mp4']");
|
||||
$assert_session->elementExists('css', "video > source[src='$file2_url'][type='video/mp4']");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display the file entity as an audio tag.
|
||||
*
|
||||
* Available variables:
|
||||
* - attributes: An array of HTML attributes, intended to be added to the
|
||||
* audio tag.
|
||||
* - files: And array of files to be added as sources for the audio tag. Each
|
||||
* element is an array with the following elements:
|
||||
* - file: The full file object.
|
||||
* - source_attributes: An array of HTML attributes for to be added to the
|
||||
* source tag.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
{{ attach_library('classy/file') }}
|
||||
<audio {{ attributes }}>
|
||||
{% for file in files %}
|
||||
<source {{ file.source_attributes }} />
|
||||
{% endfor %}
|
||||
</audio>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display the file entity as a video tag.
|
||||
*
|
||||
* Available variables:
|
||||
* - attributes: An array of HTML attributes, intended to be added to the
|
||||
* video tag.
|
||||
* - files: And array of files to be added as sources for the video tag. Each
|
||||
* element is an array with the following elements:
|
||||
* - file: The full file object.
|
||||
* - source_attributes: An array of HTML attributes for to be added to the
|
||||
* source tag.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
{{ attach_library('classy/file') }}
|
||||
<video {{ attributes }}>
|
||||
{% for file in files %}
|
||||
<source {{ file.source_attributes }} />
|
||||
{% endfor %}
|
||||
</video>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display the file entity as an audio tag.
|
||||
*
|
||||
* Available variables:
|
||||
* - attributes: An array of HTML attributes, intended to be added to the
|
||||
* audio tag.
|
||||
* - files: And array of files to be added as sources for the audio tag. Each
|
||||
* element is an array with the following elements:
|
||||
* - file: The full file object.
|
||||
* - source_attributes: An array of HTML attributes for to be added to the
|
||||
* source tag.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
<audio {{ attributes }}>
|
||||
{% for file in files %}
|
||||
<source {{ file.source_attributes }} />
|
||||
{% endfor %}
|
||||
</audio>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display the file entity as a video tag.
|
||||
*
|
||||
* Available variables:
|
||||
* - attributes: An array of HTML attributes, intended to be added to the
|
||||
* video tag.
|
||||
* - files: And array of files to be added as sources for the video tag. Each
|
||||
* element is an array with the following elements:
|
||||
* - file: The full file object.
|
||||
* - source_attributes: An array of HTML attributes for to be added to the
|
||||
* source tag.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
<video {{ attributes }}>
|
||||
{% for file in files %}
|
||||
<source {{ file.source_attributes }} />
|
||||
{% endfor %}
|
||||
</video>
|
||||
Loading…
Reference in New Issue