summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwebchick2018-07-26 18:18:46 (GMT)
committerwebchick2018-07-26 18:18:59 (GMT)
commit4e88aed495c8e698bff3b369e3f5c8a3035049ee (patch)
tree6652f38762fae20f101ab4d7dc62172d1d1dbc7e
parent33511d354c7d6c10e2660898af769ec372efc7f0 (diff)
Issue #2938116 by samuel.mortenson, sjerdo, jefuri, chr.fritsch, yogeshmpawar, starshaped, phenaproxima, jibran, webchick, seanB, Berdir, lauriii, xjm, tstoeckler, dawehner, benjifisher, marcoscano, bdimaggio, martin107, mtodor, slashrsm, Gábor Hojtsy, ckrina, yoroy: Allow media to be uploaded with the Media Library field widget
(cherry picked from commit 53d521a361869d74865933f411694daccad15de2)
-rw-r--r--core/modules/media_library/config/install/core.entity_form_mode.media.media_library.yml9
-rw-r--r--core/modules/media_library/config/optional/core.entity_form_display.media.audio.media_library.yml26
-rw-r--r--core/modules/media_library/config/optional/core.entity_form_display.media.file.media_library.yml26
-rw-r--r--core/modules/media_library/config/optional/core.entity_form_display.media.image.media_library.yml36
-rw-r--r--core/modules/media_library/config/optional/core.entity_form_display.media.video.media_library.yml26
-rw-r--r--core/modules/media_library/css/media_library.theme.css38
-rw-r--r--core/modules/media_library/media_library.module32
-rw-r--r--core/modules/media_library/media_library.routing.yml6
-rw-r--r--core/modules/media_library/src/Form/MediaLibraryUploadForm.php615
-rw-r--r--core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php68
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_four.default.yml69
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_four.media_library.yml44
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_three.default.yml60
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_three.media_library.yml36
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_three.default.yml52
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_four.field_media_extra_image.yml37
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_four.field_media_test_image.yml37
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_three.field_media_test_image.yml37
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.basic_page.field_twin_media.yml2
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_extra_image.yml29
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_image.yml29
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_four.yml12
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_three.yml12
-rw-r--r--core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml1
-rw-r--r--core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php109
25 files changed, 1412 insertions, 36 deletions
diff --git a/core/modules/media_library/config/install/core.entity_form_mode.media.media_library.yml b/core/modules/media_library/config/install/core.entity_form_mode.media.media_library.yml
new file mode 100644
index 0000000..7889cd0
--- /dev/null
+++ b/core/modules/media_library/config/install/core.entity_form_mode.media.media_library.yml
@@ -0,0 +1,9 @@
+langcode: en
+status: true
+dependencies:
+ module:
+ - media
+id: media.media_library
+label: 'Media library'
+targetEntityType: media
+cache: true
diff --git a/core/modules/media_library/config/optional/core.entity_form_display.media.audio.media_library.yml b/core/modules/media_library/config/optional/core.entity_form_display.media.audio.media_library.yml
new file mode 100644
index 0000000..56df385
--- /dev/null
+++ b/core/modules/media_library/config/optional/core.entity_form_display.media.audio.media_library.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - core.entity_form_mode.media.media_library
+ - field.field.media.audio.field_media_audio_file
+ - media.type.audio
+id: media.audio.media_library
+targetEntityType: media
+bundle: audio
+mode: media_library
+content:
+ name:
+ type: string_textfield
+ weight: 0
+ region: content
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+hidden:
+ created: true
+ field_media_audio_file: true
+ path: true
+ status: true
+ uid: true
diff --git a/core/modules/media_library/config/optional/core.entity_form_display.media.file.media_library.yml b/core/modules/media_library/config/optional/core.entity_form_display.media.file.media_library.yml
new file mode 100644
index 0000000..a0a5d49
--- /dev/null
+++ b/core/modules/media_library/config/optional/core.entity_form_display.media.file.media_library.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - core.entity_form_mode.media.media_library
+ - field.field.media.file.field_media_file
+ - media.type.file
+id: media.file.media_library
+targetEntityType: media
+bundle: file
+mode: media_library
+content:
+ name:
+ type: string_textfield
+ weight: 0
+ region: content
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+hidden:
+ created: true
+ field_media_file: true
+ path: true
+ status: true
+ uid: true
diff --git a/core/modules/media_library/config/optional/core.entity_form_display.media.image.media_library.yml b/core/modules/media_library/config/optional/core.entity_form_display.media.image.media_library.yml
new file mode 100644
index 0000000..68ca01a
--- /dev/null
+++ b/core/modules/media_library/config/optional/core.entity_form_display.media.image.media_library.yml
@@ -0,0 +1,36 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - core.entity_form_mode.media.media_library
+ - field.field.media.image.field_media_image
+ - image.style.thumbnail
+ - media.type.image
+ module:
+ - image
+id: media.image.media_library
+targetEntityType: media
+bundle: image
+mode: media_library
+content:
+ field_media_image:
+ type: image_image
+ weight: 1
+ region: content
+ settings:
+ progress_indicator: throbber
+ preview_image_style: thumbnail
+ third_party_settings: { }
+ name:
+ type: string_textfield
+ weight: 0
+ region: content
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+hidden:
+ created: true
+ path: true
+ status: true
+ uid: true
diff --git a/core/modules/media_library/config/optional/core.entity_form_display.media.video.media_library.yml b/core/modules/media_library/config/optional/core.entity_form_display.media.video.media_library.yml
new file mode 100644
index 0000000..b7caf5d
--- /dev/null
+++ b/core/modules/media_library/config/optional/core.entity_form_display.media.video.media_library.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - core.entity_form_mode.media.media_library
+ - field.field.media.video.field_media_video_file
+ - media.type.video
+id: media.video.media_library
+targetEntityType: media
+bundle: video
+mode: media_library
+content:
+ name:
+ type: string_textfield
+ weight: 0
+ region: content
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+hidden:
+ created: true
+ field_media_video_file: true
+ path: true
+ status: true
+ uid: true
diff --git a/core/modules/media_library/css/media_library.theme.css b/core/modules/media_library/css/media_library.theme.css
index 5aab3c5..4f04445 100644
--- a/core/modules/media_library/css/media_library.theme.css
+++ b/core/modules/media_library/css/media_library.theme.css
@@ -198,6 +198,44 @@
border-color: #40b6ff;
}
+/* Style the wrappers around new media and files */
+.media-library-upload__media,
+.media-library-upload__file {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 20px 0 20px 0;
+}
+
+.media-library-upload__file {
+ align-items: center;
+}
+
+.media-library-upload__file-label {
+ margin-right: 10px;
+}
+
+/* @todo Remove in https://www.drupal.org/project/drupal/issues/2987921 */
+.media-library-upload__source-field .file,
+.media-library-upload__source-field .button,
+.media-library-upload__source-field .image-preview,
+.media-library-upload__source-field .form-type-managed-file > label,
+.media-library-upload__source-field .file-size {
+ display: none;
+}
+
+.media-library-upload__media-preview {
+ margin-right: 20px;
+ width: 220px;
+ background: #ebebeb;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.media-library-upload__media-preview img {
+ display: block;
+}
+
/* @todo Remove or re-work in https://www.drupal.org/node/2985168 */
.media-library-widget .media-library-item__name a,
.media-library-view.view-display-id-widget .media-library-item__name a {
diff --git a/core/modules/media_library/media_library.module b/core/modules/media_library/media_library.module
index b72a4d4..977da24 100644
--- a/core/modules/media_library/media_library.module
+++ b/core/modules/media_library/media_library.module
@@ -6,11 +6,13 @@
*/
use Drupal\Component\Utility\UrlHelper;
+use Drupal\Component\Serialization\Json;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Template\Attribute;
+use Drupal\Core\Url;
use Drupal\views\Form\ViewsForm;
use Drupal\views\Plugin\views\cache\CachePluginBase;
use Drupal\views\Plugin\views\query\QueryPluginBase;
@@ -43,6 +45,36 @@ function media_library_theme() {
}
/**
+ * Implements hook_preprocess_view().
+ *
+ * Adds a link to add media above the view.
+ */
+function media_library_preprocess_views_view(&$variables) {
+ $view = $variables['view'];
+ if ($view->id() === 'media_library' && $view->current_display === 'widget') {
+ $url = Url::fromRoute('media_library.upload');
+ if ($url->access()) {
+ $url->setOption('query', \Drupal::request()->query->all());
+ $variables['header']['add_media'] = [
+ '#type' => 'link',
+ '#title' => t('Add media'),
+ '#url' => $url,
+ '#attributes' => [
+ 'class' => ['button', 'button-action', 'button--primary', 'use-ajax'],
+ 'data-dialog-type' => 'modal',
+ 'data-dialog-options' => Json::encode([
+ 'dialogClass' => 'media-library-widget-modal',
+ 'height' => '75%',
+ 'width' => '75%',
+ 'title' => t('Add media'),
+ ]),
+ ],
+ ];
+ }
+ }
+}
+
+/**
* Implements hook_views_post_render().
*/
function media_library_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
diff --git a/core/modules/media_library/media_library.routing.yml b/core/modules/media_library/media_library.routing.yml
new file mode 100644
index 0000000..1724760
--- /dev/null
+++ b/core/modules/media_library/media_library.routing.yml
@@ -0,0 +1,6 @@
+media_library.upload:
+ path: '/admin/content/media-widget-upload'
+ defaults:
+ _form: '\Drupal\media_library\Form\MediaLibraryUploadForm'
+ requirements:
+ _custom_access: '\Drupal\media_library\Form\MediaLibraryUploadForm::access'
diff --git a/core/modules/media_library/src/Form/MediaLibraryUploadForm.php b/core/modules/media_library/src/Form/MediaLibraryUploadForm.php
new file mode 100644
index 0000000..3ed96b4
--- /dev/null
+++ b/core/modules/media_library/src/Form/MediaLibraryUploadForm.php
@@ -0,0 +1,615 @@
+<?php
+
+namespace Drupal\media_library\Form;
+
+use Drupal\Core\Access\AccessResultAllowed;
+use Drupal\Core\Ajax\AjaxResponse;
+use Drupal\Core\Ajax\CloseDialogCommand;
+use Drupal\Core\Ajax\InvokeCommand;
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\ElementInfoManagerInterface;
+use Drupal\file\FileInterface;
+use Drupal\file\Plugin\Field\FieldType\FileFieldItemList;
+use Drupal\file\Plugin\Field\FieldType\FileItem;
+use Drupal\media\MediaInterface;
+use Drupal\media\MediaTypeInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+
+/**
+ * Creates a form to create media entities from uploaded files.
+ *
+ * @internal
+ */
+class MediaLibraryUploadForm extends FormBase {
+
+ /**
+ * The element info manager.
+ *
+ * @var \Drupal\Core\Render\ElementInfoManagerInterface
+ */
+ protected $elementInfo;
+
+ /**
+ * The entity type manager.
+ *
+ * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+ */
+ protected $entityTypeManager;
+
+ /**
+ * Media types the current user has access to.
+ *
+ * @var \Drupal\media\MediaTypeInterface[]
+ */
+ protected $types;
+
+ /**
+ * The media being processed.
+ *
+ * @var \Drupal\media\MediaInterface[]
+ */
+ protected $media = [];
+
+ /**
+ * The files waiting for type selection.
+ *
+ * @var \Drupal\file\FileInterface[]
+ */
+ protected $files = [];
+
+ /**
+ * Indicates whether the 'medium' image style exists.
+ *
+ * @var bool
+ */
+ protected $mediumStyleExists = FALSE;
+
+ /**
+ * Constructs a new MediaLibraryUploadForm.
+ *
+ * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+ * The entity type manager.
+ * @param \Drupal\Core\Render\ElementInfoManagerInterface $element_info
+ * The element info manager.
+ */
+ public function __construct(EntityTypeManagerInterface $entity_type_manager, ElementInfoManagerInterface $element_info) {
+ $this->entityTypeManager = $entity_type_manager;
+ $this->elementInfo = $element_info;
+ $this->mediumStyleExists = !empty($entity_type_manager->getStorage('image_style')->load('medium'));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('entity_type.manager'),
+ $container->get('element_info')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormId() {
+ return 'media_library_upload_form';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildForm(array $form, FormStateInterface $form_state) {
+ $form['#prefix'] = '<div id="media-library-upload-wrapper">';
+ $form['#suffix'] = '</div>';
+
+ $form['#attached']['library'][] = 'media_library/style';
+
+ $form['#attributes']['class'][] = 'media-library-upload';
+
+ if (empty($this->media) && empty($this->files)) {
+ $process = (array) $this->elementInfo->getInfoProperty('managed_file', '#process', []);
+ $upload_validators = $this->mergeUploadValidators($this->getTypes());
+ $form['upload'] = [
+ '#type' => 'managed_file',
+ '#title' => $this->t('Upload'),
+ // @todo Move validation in https://www.drupal.org/node/2988215
+ '#process' => array_merge(['::validateUploadElement'], $process, ['::processUploadElement']),
+ '#upload_validators' => $upload_validators,
+ ];
+ $form['upload_help'] = [
+ '#theme' => 'file_upload_help',
+ '#description' => $this->t('Upload files here to add new media.'),
+ '#upload_validators' => $upload_validators,
+ ];
+ $remaining = $this->getRequest()->query->get('media_library_remaining');
+ if ($remaining) {
+ $form['upload']['#multiple'] = $remaining > 1;
+ $form['upload']['#cardinality'] = $form['upload_help']['#cardinality'] = (int) $remaining;
+ }
+ }
+ else {
+ $form['media'] = [
+ '#type' => 'container',
+ ];
+ foreach ($this->media as $i => $media) {
+ $source_field = $media->getSource()
+ ->getSourceFieldDefinition($media->bundle->entity)
+ ->getName();
+
+ $element = [
+ '#type' => 'container',
+ '#attributes' => [
+ 'class' => [
+ 'media-library-upload__media',
+ ],
+ ],
+ 'preview' => [
+ '#type' => 'container',
+ '#attributes' => [
+ 'class' => [
+ 'media-library-upload__media-preview',
+ ],
+ ],
+ ],
+ 'fields' => [
+ '#type' => 'container',
+ '#attributes' => [
+ 'class' => [
+ 'media-library-upload__media-fields',
+ ],
+ ],
+ // Parents is set here as it is used in the form display.
+ '#parents' => ['media', $i, 'fields'],
+ ],
+ ];
+ // @todo Make this configurable in https://www.drupal.org/node/2988223
+ if ($this->mediumStyleExists && $thumbnail_uri = $media->getSource()->getMetadata($media, 'thumbnail_uri')) {
+ $element['preview']['thumbnail'] = [
+ '#theme' => 'image_style',
+ '#style_name' => 'medium',
+ '#uri' => $thumbnail_uri,
+ ];
+ }
+ EntityFormDisplay::collectRenderDisplay($media, 'media_library')
+ ->buildForm($media, $element['fields'], $form_state);
+ // We hide certain elements in the image widget with CSS.
+ if (isset($element['fields'][$source_field])) {
+ $element['fields'][$source_field]['#attributes']['class'][] = 'media-library-upload__source-field';
+ }
+ if (isset($element['fields']['revision_log_message'])) {
+ $element['fields']['revision_log_message']['#access'] = FALSE;
+ }
+ $form['media'][$i] = $element;
+ }
+
+ $form['files'] = [
+ '#type' => 'container',
+ ];
+ foreach ($this->files as $i => $file) {
+ $types = $this->filterTypesThatAcceptFile($file, $this->getTypes());
+ $form['files'][$i] = [
+ '#type' => 'container',
+ '#attributes' => [
+ 'class' => [
+ 'media-library-upload__file',
+ ],
+ ],
+ 'help' => [
+ '#markup' => '<strong class="media-library-upload__file-label">' . $this->t('Select a media type for %filename:', [
+ '%filename' => $file->getFilename(),
+ ]) . '</strong>',
+ ],
+ ];
+ foreach ($types as $type) {
+ $form['files'][$i][$type->id()] = [
+ '#type' => 'submit',
+ '#media_library_index' => $i,
+ '#media_library_type' => $type->id(),
+ '#value' => $type->label(),
+ '#submit' => ['::selectType'],
+ '#ajax' => [
+ 'callback' => '::updateFormCallback',
+ 'wrapper' => 'media-library-upload-wrapper',
+ ],
+ '#limit_validation_errors' => [['files', $i, $type->id()]],
+ ];
+ }
+ }
+
+ $form['actions'] = [
+ '#type' => 'actions',
+ ];
+ $form['actions']['submit'] = [
+ '#type' => 'submit',
+ '#value' => $this->t('Save'),
+ '#ajax' => [
+ 'callback' => '::updateWidget',
+ 'wrapper' => 'media-library-upload-wrapper',
+ ],
+ ];
+ }
+
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateForm(array &$form, FormStateInterface $form_state) {
+ if (count($this->files)) {
+ $form_state->setError($form['files'], $this->t('Please select a media type for all files.'));
+ }
+ foreach ($this->media as $i => $media) {
+ $form_display = EntityFormDisplay::collectRenderDisplay($media, 'media_library');
+ $form_display->extractFormValues($media, $form['media'][$i]['fields'], $form_state);
+ $form_display->validateFormValues($media, $form['media'][$i]['fields'], $form_state);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitForm(array &$form, FormStateInterface $form_state) {
+ foreach ($this->media as $i => $media) {
+ EntityFormDisplay::collectRenderDisplay($media, 'media_library')
+ ->extractFormValues($media, $form['media'][$i]['fields'], $form_state);
+ $source_field = $media->getSource()->getSourceFieldDefinition($media->bundle->entity)->getName();
+ /** @var \Drupal\file\FileInterface $file */
+ $file = $media->get($source_field)->entity;
+ $file->setPermanent();
+ $file->save();
+ $media->save();
+ }
+ }
+
+ /**
+ * AJAX callback to select a media type for a file.
+ *
+ * @param array $form
+ * An associative array containing the structure of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The current state of the form.
+ *
+ * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+ * If the triggering element is missing required properties.
+ */
+ public function selectType(array &$form, FormStateInterface $form_state) {
+ $element = $form_state->getTriggeringElement();
+ if (!isset($element['#media_library_index']) || !isset($element['#media_library_type'])) {
+ throw new BadRequestHttpException('The "#media_library_index" and "#media_library_type" properties on the triggering element are required for type selection.');
+ }
+ $i = $element['#media_library_index'];
+ $type = $element['#media_library_type'];
+ $this->media[] = $this->createMediaEntity($this->files[$i], $this->getTypes()[$type]);
+ unset($this->files[$i]);
+ $form_state->setRebuild();
+ }
+
+ /**
+ * AJAX callback to update the field widget.
+ *
+ * @param array $form
+ * An associative array containing the structure of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The current state of the form.
+ *
+ * @return \Drupal\Core\Ajax\AjaxResponse
+ * A command to send the selection to the current field widget.
+ *
+ * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+ * If the "media_library_widget_id" query parameter is not present.
+ */
+ public function updateWidget(array &$form, FormStateInterface $form_state) {
+ if ($form_state->getErrors()) {
+ return $form;
+ }
+ $widget_id = $this->getRequest()->query->get('media_library_widget_id');
+ if (!$widget_id || !is_string($widget_id)) {
+ throw new BadRequestHttpException('The "media_library_widget_id" query parameter is required and must be a string.');
+ }
+ $mids = array_map(function (MediaInterface $media) {
+ return $media->id();
+ }, $this->media);
+ // Pass the selection to the field widget based on the current widget ID.
+ return (new AjaxResponse())
+ ->addCommand(new InvokeCommand("[data-media-library-widget-value=\"$widget_id\"]", 'val', [implode(',', $mids)]))
+ ->addCommand(new InvokeCommand("[data-media-library-widget-update=\"$widget_id\"]", 'trigger', ['mousedown']))
+ ->addCommand(new CloseDialogCommand());
+ }
+
+ /**
+ * Processes an upload (managed_file) element.
+ *
+ * @param array $element
+ * The upload element.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The form state.
+ *
+ * @return array
+ * The processed upload element.
+ */
+ public function processUploadElement(array $element, FormStateInterface $form_state) {
+ $element['upload_button']['#submit'] = ['::uploadButtonSubmit'];
+ $element['upload_button']['#ajax'] = [
+ 'callback' => '::updateFormCallback',
+ 'wrapper' => 'media-library-upload-wrapper',
+ ];
+ return $element;
+ }
+
+ /**
+ * Validates the upload element.
+ *
+ * @param array $element
+ * The upload element.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The form state.
+ *
+ * @return array
+ * The processed upload element.
+ */
+ public function validateUploadElement(array $element, FormStateInterface $form_state) {
+ if ($form_state->getErrors()) {
+ $element['#value'] = [];
+ }
+ $values = $form_state->getValue('upload', []);
+ if (count($values['fids']) > $element['#cardinality']) {
+ $form_state->setError($element, $this->t('A maximum of @count files can be uploaded.', [
+ '@count' => $element['#cardinality'],
+ ]));
+ $form_state->setValue('upload', []);
+ $element['#value'] = [];
+ }
+ return $element;
+ }
+
+ /**
+ * Submit handler for the upload button, inside the managed_file element.
+ *
+ * @param array $form
+ * The form render array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The form state.
+ */
+ public function uploadButtonSubmit(array $form, FormStateInterface $form_state) {
+ $fids = $form_state->getValue('upload', []);
+ $files = $this->entityTypeManager->getStorage('file')->loadMultiple($fids);
+ /** @var \Drupal\file\FileInterface $file */
+ foreach ($files as $file) {
+ $types = $this->filterTypesThatAcceptFile($file, $this->getTypes());
+ if (!empty($types)) {
+ if (count($types) === 1) {
+ $this->media[] = $this->createMediaEntity($file, reset($types));
+ }
+ else {
+ $this->files[] = $file;
+ }
+ }
+ }
+ $form_state->setRebuild();
+ }
+
+ /**
+ * Creates a new, unsaved media entity.
+ *
+ * @param \Drupal\file\FileInterface $file
+ * A file for the media source field.
+ * @param \Drupal\media\MediaTypeInterface $type
+ * A media type.
+ *
+ * @return \Drupal\media\MediaInterface
+ * An unsaved media entity.
+ *
+ * @throws \Exception
+ * If a file operation failed when moving the upload.
+ */
+ protected function createMediaEntity(FileInterface $file, MediaTypeInterface $type) {
+ $media = $this->entityTypeManager->getStorage('media')->create([
+ 'bundle' => $type->id(),
+ 'name' => $file->getFilename(),
+ ]);
+ $source_field = $type->getSource()->getSourceFieldDefinition($type)->getName();
+ $location = $this->getUploadLocationForType($media->bundle->entity);
+ if (!file_prepare_directory($location, FILE_CREATE_DIRECTORY)) {
+ throw new \Exception("The destination directory '$location' is not writable");
+ }
+ $file = file_move($file, $location);
+ if (!$file) {
+ throw new \Exception("Unable to move file to '$location'");
+ }
+ $media->set($source_field, $file->id());
+ return $media;
+ }
+
+ /**
+ * AJAX callback for refreshing the entire form.
+ *
+ * @param array $form
+ * The form render array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The form state.
+ *
+ * @return array
+ * The form render array.
+ */
+ public function updateFormCallback(array &$form, FormStateInterface $form_state) {
+ return $form;
+ }
+
+ /**
+ * Access callback to check that the user can create file based media.
+ *
+ * @return \Drupal\Core\Access\AccessResultInterface
+ * The access result.
+ */
+ public function access() {
+ return AccessResultAllowed::allowedIf(count($this->getTypes()))->mergeCacheMaxAge(0);
+ }
+
+ /**
+ * Returns media types which use files that the current user can create.
+ *
+ * @todo Move in https://www.drupal.org/node/2987924
+ *
+ * @return \Drupal\media\MediaTypeInterface[]
+ * A list of media types that are valid for this form.
+ */
+ protected function getTypes() {
+ // Cache results if possible.
+ if (!isset($this->types)) {
+ $media_type_storage = $this->entityTypeManager->getStorage('media_type');
+ $allowed_types = _media_library_get_allowed_types() ?: NULL;
+ $types = $media_type_storage->loadMultiple($allowed_types);
+ $types = $this->filterTypesWithFileSource($types);
+ $types = $this->filterTypesWithCreateAccess($types);
+ $this->types = $types;
+ }
+ return $this->types;
+ }
+
+ /**
+ * Filters media types that accept a given file.
+ *
+ * @todo Move in https://www.drupal.org/node/2987924
+ *
+ * @param \Drupal\file\FileInterface $file
+ * A file entity.
+ * @param \Drupal\media\MediaTypeInterface[] $types
+ * An array of available media types.
+ *
+ * @return \Drupal\media\MediaTypeInterface[]
+ * An array of media types that accept the file.
+ */
+ protected function filterTypesThatAcceptFile(FileInterface $file, array $types) {
+ $types = $this->filterTypesWithFileSource($types);
+ return array_filter($types, function (MediaTypeInterface $type) use ($file) {
+ $validators = $this->getUploadValidatorsForType($type);
+ $errors = file_validate($file, $validators);
+ return empty($errors);
+ });
+ }
+
+ /**
+ * Filters an array of media types that accept file sources.
+ *
+ * @todo Move in https://www.drupal.org/node/2987924
+ *
+ * @param \Drupal\media\MediaTypeInterface[] $types
+ * An array of media types.
+ *
+ * @return \Drupal\media\MediaTypeInterface[]
+ * An array of media types that accept file sources.
+ */
+ protected function filterTypesWithFileSource(array $types) {
+ return array_filter($types, function (MediaTypeInterface $type) {
+ return is_a($type->getSource()->getSourceFieldDefinition($type)->getClass(), FileFieldItemList::class, TRUE);
+ });
+ }
+
+ /**
+ * Merges file upload validators for an array of media types.
+ *
+ * @todo Move in https://www.drupal.org/node/2987924
+ *
+ * @param \Drupal\media\MediaTypeInterface[] $types
+ * An array of media types.
+ *
+ * @return array
+ * An array suitable for passing to file_save_upload() or the file field
+ * element's '#upload_validators' property.
+ */
+ protected function mergeUploadValidators(array $types) {
+ $max_size = 0;
+ $extensions = [];
+ $types = $this->filterTypesWithFileSource($types);
+ foreach ($types as $type) {
+ $validators = $this->getUploadValidatorsForType($type);
+ if (isset($validators['file_validate_size'])) {
+ $max_size = max($max_size, $validators['file_validate_size'][0]);
+ }
+ if (isset($validators['file_validate_extensions'])) {
+ $extensions = array_unique(array_merge($extensions, explode(' ', $validators['file_validate_extensions'][0])));
+ }
+ }
+ // If no field defines a max size, default to the system wide setting.
+ if ($max_size === 0) {
+ $max_size = file_upload_max_size();
+ }
+ return [
+ 'file_validate_extensions' => [implode(' ', $extensions)],
+ 'file_validate_size' => [$max_size],
+ ];
+ }
+
+ /**
+ * Gets upload validators for a given media type.
+ *
+ * @todo Move in https://www.drupal.org/node/2987924
+ *
+ * @param \Drupal\media\MediaTypeInterface $type
+ * A media type.
+ *
+ * @return array
+ * An array suitable for passing to file_save_upload() or the file field
+ * element's '#upload_validators' property.
+ */
+ protected function getUploadValidatorsForType(MediaTypeInterface $type) {
+ return $this->getFileItemForType($type)->getUploadValidators();
+ }
+
+ /**
+ * Gets upload destination for a given media type.
+ *
+ * @todo Move in https://www.drupal.org/node/2987924
+ *
+ * @param \Drupal\media\MediaTypeInterface $type
+ * A media type.
+ *
+ * @return string
+ * An unsanitized file directory URI with tokens replaced.
+ */
+ protected function getUploadLocationForType(MediaTypeInterface $type) {
+ return $this->getFileItemForType($type)->getUploadLocation();
+ }
+
+ /**
+ * Creates a file item for a given media type.
+ *
+ * @todo Move in https://www.drupal.org/node/2987924
+ *
+ * @param \Drupal\media\MediaTypeInterface $type
+ * A media type.
+ *
+ * @return \Drupal\file\Plugin\Field\FieldType\FileItem
+ * The file item.
+ */
+ protected function getFileItemForType(MediaTypeInterface $type) {
+ $source = $type->getSource();
+ $source_data_definition = FieldItemDataDefinition::create($source->getSourceFieldDefinition($type));
+ return new FileItem($source_data_definition);
+ }
+
+ /**
+ * Filters an array of media types that can be created by the current user.
+ *
+ * @todo Move in https://www.drupal.org/node/2987924
+ *
+ * @param \Drupal\media\MediaTypeInterface[] $types
+ * An array of media types.
+ *
+ * @return \Drupal\media\MediaTypeInterface[]
+ * An array of media types that accept file sources.
+ */
+ protected function filterTypesWithCreateAccess(array $types) {
+ $access_handler = $this->entityTypeManager->getAccessControlHandler('media');
+ return array_filter($types, function (MediaTypeInterface $type) use ($access_handler) {
+ return $access_handler->createAccess($type->id());
+ });
+ }
+
+}
diff --git a/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
index 86aa2e9..2908002 100644
--- a/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
+++ b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
@@ -124,31 +124,6 @@ class MediaLibraryWidget extends WidgetBase implements ContainerFactoryPluginInt
],
];
- // @todo Remove in https://www.drupal.org/project/drupal/issues/2938116
- $allowed_bundles = !empty($element['#target_bundles']) ? $element['#target_bundles'] : [];
- $add_url = _media_get_add_url($allowed_bundles);
- if ($add_url) {
- $element['create_help'] = [
- '#type' => 'container',
- ];
- $element['create_help']['label'] = [
- '#type' => 'html_tag',
- '#tag' => 'h4',
- '#attributes' => [
- 'class' => ['label'],
- ],
- '#value' => $this->t('Create new media'),
- ];
- $element['create_help']['description'] = [
- '#type' => 'html_tag',
- '#tag' => 'div',
- '#attributes' => [
- 'class' => ['description'],
- ],
- '#value' => $this->t('Create your media on the <a href=":add_page" target="_blank">media add page</a> (opens a new window), then select it in the library.', [':add_page' => $add_url]),
- ];
- }
-
$element['selection'] = [
'#type' => 'container',
'#attributes' => [
@@ -242,6 +217,18 @@ class MediaLibraryWidget extends WidgetBase implements ContainerFactoryPluginInt
$element['#description'] .= '<br />' . $cardinality_message;
}
+ $query = [
+ 'media_library_widget_id' => $field_name . $id_suffix,
+ 'media_library_allowed_types' => $element['#target_bundles'],
+ 'media_library_remaining' => $cardinality_unlimited ? FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED : $remaining,
+ ];
+ $dialog_options = Json::encode([
+ 'dialogClass' => 'media-library-widget-modal',
+ 'height' => '75%',
+ 'width' => '75%',
+ 'title' => $this->t('Media library'),
+ ]);
+
// Add a button that will load the Media library in a modal using AJAX.
$element['media_library_open_button'] = [
'#type' => 'link',
@@ -249,27 +236,36 @@ class MediaLibraryWidget extends WidgetBase implements ContainerFactoryPluginInt
'#name' => $field_name . '-media-library-open-button' . $id_suffix,
// @todo Make the view configurable in https://www.drupal.org/project/drupal/issues/2971209
'#url' => Url::fromRoute('view.media_library.widget', [], [
- 'query' => [
- 'media_library_widget_id' => $field_name . $id_suffix,
- 'media_library_allowed_types' => $element['#target_bundles'],
- 'media_library_remaining' => $cardinality_unlimited ? FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED : $remaining,
- ],
+ 'query' => $query,
]),
'#attributes' => [
'class' => ['button', 'use-ajax', 'media-library-open-button'],
'data-dialog-type' => 'modal',
- 'data-dialog-options' => Json::encode([
- 'dialogClass' => 'media-library-widget-modal',
- 'height' => '75%',
- 'width' => '75%',
- 'title' => $this->t('Media library'),
- ]),
+ 'data-dialog-options' => $dialog_options,
],
// Prevent errors in other widgets from preventing addition.
'#limit_validation_errors' => $limit_validation_errors,
'#access' => $cardinality_unlimited || $remaining > 0,
];
+ $add_url = Url::fromRoute('media_library.upload', [], [
+ 'query' => $query,
+ ]);
+ $element['media_library_add_button'] = [
+ '#type' => 'link',
+ '#title' => $this->t('Add media'),
+ '#name' => $field_name . '-media-library-add-button' . $id_suffix,
+ '#url' => $add_url,
+ '#attributes' => [
+ 'class' => ['button', 'use-ajax', 'media-library-add-button'],
+ 'data-dialog-type' => 'modal',
+ 'data-dialog-options' => $dialog_options,
+ ],
+ // Prevent errors in other widgets from preventing addition.
+ '#limit_validation_errors' => $limit_validation_errors,
+ '#access' => $add_url->access() && ($cardinality_unlimited || $remaining > 0),
+ ];
+
// This hidden field and button are used to add new items to the widget.
$element['media_library_selection'] = [
'#type' => 'hidden',
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_four.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_four.default.yml
new file mode 100644
index 0000000..40d4d1b
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_four.default.yml
@@ -0,0 +1,69 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.field.media.type_four.field_media_test_image
+ - field.field.media.type_four.field_media_extra_image
+ - image.style.medium
+ - media.type.type_four
+ module:
+ - image
+ - path
+id: media.type_four.default
+targetEntityType: media
+bundle: type_four
+mode: default
+content:
+ created:
+ type: datetime_timestamp
+ weight: 10
+ region: content
+ settings: { }
+ third_party_settings: { }
+ field_media_test_image:
+ weight: 0
+ settings:
+ progress_indicator: throbber
+ preview_image_style: medium
+ third_party_settings: { }
+ type: image_image
+ region: content
+ field_media_extra_image:
+ weight: 1
+ settings:
+ progress_indicator: throbber
+ preview_image_style: medium
+ third_party_settings: { }
+ type: image_image
+ region: content
+ name:
+ type: string_textfield
+ weight: -5
+ region: content
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+ path:
+ type: path
+ weight: 30
+ region: content
+ settings: { }
+ third_party_settings: { }
+ status:
+ type: boolean_checkbox
+ settings:
+ display_label: true
+ weight: 100
+ region: content
+ third_party_settings: { }
+ uid:
+ type: entity_reference_autocomplete
+ weight: 5
+ settings:
+ match_operator: CONTAINS
+ size: 60
+ placeholder: ''
+ region: content
+ third_party_settings: { }
+hidden: { }
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_four.media_library.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_four.media_library.yml
new file mode 100644
index 0000000..0abef48
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_four.media_library.yml
@@ -0,0 +1,44 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - core.entity_form_mode.media.media_library
+ - field.field.media.type_four.field_media_test_image
+ - image.style.thumbnail
+ - media.type.type_four
+ module:
+ - image
+id: media.type_four.media_library
+targetEntityType: media
+bundle: type_four
+mode: media_library
+content:
+ field_media_test_image:
+ weight: 2
+ settings:
+ progress_indicator: throbber
+ preview_image_style: thumbnail
+ third_party_settings: { }
+ type: image_image
+ region: content
+ field_media_extra_image:
+ weight: 1
+ settings:
+ progress_indicator: throbber
+ preview_image_style: medium
+ third_party_settings: { }
+ type: image_image
+ region: content
+ name:
+ type: string_textfield
+ weight: 0
+ region: content
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+hidden:
+ created: true
+ path: true
+ status: true
+ uid: true
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_three.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_three.default.yml
new file mode 100644
index 0000000..ea7248e
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_three.default.yml
@@ -0,0 +1,60 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.field.media.type_three.field_media_test_image
+ - image.style.medium
+ - media.type.type_three
+ module:
+ - image
+ - path
+id: media.type_three.default
+targetEntityType: media
+bundle: type_three
+mode: default
+content:
+ created:
+ type: datetime_timestamp
+ weight: 10
+ region: content
+ settings: { }
+ third_party_settings: { }
+ field_media_test_image:
+ weight: 0
+ settings:
+ progress_indicator: throbber
+ preview_image_style: medium
+ third_party_settings: { }
+ type: image_image
+ region: content
+ name:
+ type: string_textfield
+ weight: -5
+ region: content
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+ path:
+ type: path
+ weight: 30
+ region: content
+ settings: { }
+ third_party_settings: { }
+ status:
+ type: boolean_checkbox
+ settings:
+ display_label: true
+ weight: 100
+ region: content
+ third_party_settings: { }
+ uid:
+ type: entity_reference_autocomplete
+ weight: 5
+ settings:
+ match_operator: CONTAINS
+ size: 60
+ placeholder: ''
+ region: content
+ third_party_settings: { }
+hidden: { }
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_three.media_library.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_three.media_library.yml
new file mode 100644
index 0000000..c7fdfc7
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_three.media_library.yml
@@ -0,0 +1,36 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - core.entity_form_mode.media.media_library
+ - field.field.media.type_three.field_media_test_image
+ - image.style.thumbnail
+ - media.type.type_three
+ module:
+ - image
+id: media.type_three.media_library
+targetEntityType: media
+bundle: type_three
+mode: media_library
+content:
+ field_media_test_image:
+ weight: 1
+ settings:
+ progress_indicator: throbber
+ preview_image_style: thumbnail
+ third_party_settings: { }
+ type: image_image
+ region: content
+ name:
+ type: string_textfield
+ weight: 0
+ region: content
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+hidden:
+ created: true
+ path: true
+ status: true
+ uid: true
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_three.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_three.default.yml
new file mode 100644
index 0000000..de6650e
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_three.default.yml
@@ -0,0 +1,52 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.field.media.type_three.field_media_test_image
+ - image.style.thumbnail
+ - media.type.type_three
+ module:
+ - image
+ - user
+id: media.type_three.default
+targetEntityType: media
+bundle: type_three
+mode: default
+content:
+ created:
+ label: hidden
+ type: timestamp
+ weight: 0
+ region: content
+ settings:
+ date_format: medium
+ custom_date_format: ''
+ timezone: ''
+ third_party_settings: { }
+ field_media_test_image:
+ weight: 6
+ label: above
+ settings:
+ image_style: ''
+ image_link: ''
+ third_party_settings: { }
+ type: image
+ region: content
+ thumbnail:
+ type: image
+ weight: 5
+ label: hidden
+ settings:
+ image_style: thumbnail
+ image_link: ''
+ region: content
+ third_party_settings: { }
+ uid:
+ label: hidden
+ type: author
+ weight: 0
+ region: content
+ settings: { }
+ third_party_settings: { }
+hidden:
+ name: true
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_four.field_media_extra_image.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_four.field_media_extra_image.yml
new file mode 100644
index 0000000..3bd38cb
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_four.field_media_extra_image.yml
@@ -0,0 +1,37 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.storage.media.field_media_extra_image
+ - media.type.type_four
+ module:
+ - image
+id: media.type_three.field_media_extra_image
+field_name: field_media_extra_image
+entity_type: media
+bundle: type_four
+label: Extra Image
+description: ''
+required: false
+translatable: true
+default_value: { }
+default_value_callback: ''
+settings:
+ file_extensions: 'jpg'
+ alt_field: false
+ alt_field_required: false
+ title_field: false
+ title_field_required: false
+ max_resolution: ''
+ min_resolution: ''
+ default_image:
+ uuid: null
+ alt: ''
+ title: ''
+ width: null
+ height: null
+ file_directory: 'type-four-extra-dir'
+ max_filesize: ''
+ handler: 'default:file'
+ handler_settings: { }
+field_type: image
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_four.field_media_test_image.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_four.field_media_test_image.yml
new file mode 100644
index 0000000..e1d4e51
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_four.field_media_test_image.yml
@@ -0,0 +1,37 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.storage.media.field_media_test_image
+ - media.type.type_four
+ module:
+ - image
+id: media.type_three.field_media_test_image
+field_name: field_media_test_image
+entity_type: media
+bundle: type_four
+label: Image
+description: ''
+required: true
+translatable: true
+default_value: { }
+default_value_callback: ''
+settings:
+ file_extensions: 'jpg'
+ alt_field: true
+ alt_field_required: true
+ title_field: false
+ title_field_required: false
+ max_resolution: ''
+ min_resolution: ''
+ default_image:
+ uuid: null
+ alt: ''
+ title: ''
+ width: null
+ height: null
+ file_directory: 'type-four-dir'
+ max_filesize: ''
+ handler: 'default:file'
+ handler_settings: { }
+field_type: image
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_three.field_media_test_image.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_three.field_media_test_image.yml
new file mode 100644
index 0000000..27bce7e
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_three.field_media_test_image.yml
@@ -0,0 +1,37 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.storage.media.field_media_test_image
+ - media.type.type_three
+ module:
+ - image
+id: media.type_three.field_media_test_image
+field_name: field_media_test_image
+entity_type: media
+bundle: type_three
+label: Image
+description: ''
+required: true
+translatable: true
+default_value: { }
+default_value_callback: ''
+settings:
+ file_extensions: 'png gif jpg jpeg'
+ alt_field: true
+ alt_field_required: true
+ title_field: false
+ title_field_required: false
+ max_resolution: ''
+ min_resolution: ''
+ default_image:
+ uuid: null
+ alt: ''
+ title: ''
+ width: null
+ height: null
+ file_directory: 'type-three-dir'
+ max_filesize: ''
+ handler: 'default:file'
+ handler_settings: { }
+field_type: image
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.basic_page.field_twin_media.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.basic_page.field_twin_media.yml
index 7d4d8cd..5c874b7 100644
--- a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.basic_page.field_twin_media.yml
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.basic_page.field_twin_media.yml
@@ -22,6 +22,8 @@ settings:
target_bundles:
type_one: type_one
type_two: type_two
+ type_three: type_three
+ type_four: type_four
sort:
field: _none
auto_create: false
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_extra_image.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_extra_image.yml
new file mode 100644
index 0000000..a81f94a
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_extra_image.yml
@@ -0,0 +1,29 @@
+langcode: en
+status: true
+dependencies:
+ module:
+ - file
+ - image
+ - media
+id: media.field_media_extra_image
+field_name: field_media_extra_image
+entity_type: media
+type: image
+settings:
+ default_image:
+ uuid: null
+ alt: ''
+ title: ''
+ width: null
+ height: null
+ target_type: file
+ display_field: false
+ display_default: false
+ uri_scheme: public
+module: image
+locked: false
+cardinality: 1
+translatable: true
+indexes: { }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_image.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_image.yml
new file mode 100644
index 0000000..db94e93
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_image.yml
@@ -0,0 +1,29 @@
+langcode: en
+status: true
+dependencies:
+ module:
+ - file
+ - image
+ - media
+id: media.field_media_test_image
+field_name: field_media_test_image
+entity_type: media
+type: image
+settings:
+ default_image:
+ uuid: null
+ alt: ''
+ title: ''
+ width: null
+ height: null
+ target_type: file
+ display_field: false
+ display_default: false
+ uri_scheme: public
+module: image
+locked: false
+cardinality: 1
+translatable: true
+indexes: { }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_four.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_four.yml
new file mode 100644
index 0000000..087c34e
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_four.yml
@@ -0,0 +1,12 @@
+langcode: en
+status: true
+dependencies: { }
+id: type_four
+label: 'Type Four'
+description: ''
+source: image
+queue_thumbnail_downloads: false
+new_revision: false
+source_configuration:
+ source_field: field_media_test_image
+field_map: { }
diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_three.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_three.yml
new file mode 100644
index 0000000..536de34
--- /dev/null
+++ b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_three.yml
@@ -0,0 +1,12 @@
+langcode: en
+status: true
+dependencies: { }
+id: type_three
+label: 'Type Three'
+description: ''
+source: image
+queue_thumbnail_downloads: false
+new_revision: false
+source_configuration:
+ source_field: field_media_test_image
+field_map: { }
diff --git a/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml b/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml
index 41979c8..78582f2 100644
--- a/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml
+++ b/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml
@@ -4,6 +4,7 @@ description: 'Test module for Media library.'
package: Testing
core: 8.x
dependencies:
+ - drupal:image
- drupal:media_library
- drupal:media_test_source
- drupal:menu_ui
diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
index ab6e8a5..b92a42e 100644
--- a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
+++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php
@@ -4,6 +4,7 @@ namespace Drupal\Tests\media_library\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\media\Entity\Media;
+use Drupal\Tests\TestFileCreationTrait;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
@@ -14,6 +15,8 @@ use Drupal\user\RoleInterface;
*/
class MediaLibraryTest extends WebDriverTestBase {
+ use TestFileCreationTrait;
+
/**
* {@inheritdoc}
*/
@@ -286,4 +289,110 @@ class MediaLibraryTest extends WebDriverTestBase {
$assert_session->pageTextContains('Dog');
}
+ /**
+ * Tests that uploads in the Media library's widget works as expected.
+ */
+ public function testWidgetUpload() {
+ $assert_session = $this->assertSession();
+ $page = $this->getSession()->getPage();
+
+ foreach ($this->getTestFiles('image') as $image) {
+ $extension = pathinfo($image->filename, PATHINFO_EXTENSION);
+ if ($extension === 'png') {
+ $png_image = $image;
+ }
+ elseif ($extension === 'jpg') {
+ $jpg_image = $image;
+ }
+ }
+
+ if (!isset($png_image) || !isset($jpg_image)) {
+ $this->fail('Expected test files not present.');
+ }
+
+ // Visit a node create page.
+ $this->drupalGet('node/add/basic_page');
+
+ $file_storage = $this->container->get('entity_type.manager')->getStorage('file');
+ /** @var \Drupal\Core\File\FileSystemInterface $file_system */
+ $file_system = $this->container->get('file_system');
+
+ // Add to the twin media field using the add button directly on the widget.
+ $unlimited_button = $assert_session->elementExists('css', '.media-library-add-button[href*="field_twin_media"]');
+ $unlimited_button->click();
+ $assert_session->assertWaitOnAjaxRequest();
+
+ $page->attachFileToField('Upload', $this->container->get('file_system')->realpath($png_image->uri));
+ $assert_session->assertWaitOnAjaxRequest();
+
+ // Files are temporary until the form is saved.
+ $files = $file_storage->loadMultiple();
+ $file = array_pop($files);
+ $this->assertSame('public://type-three-dir', $file_system->dirname($file->getFileUri()));
+ $this->assertTrue($file->isTemporary());
+
+ $this->assertSame($assert_session->fieldExists('Name')->getValue(), $png_image->filename);
+ $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save');
+ $assert_session->assertWaitOnAjaxRequest();
+ $assert_session->pageTextContains('Alternative text field is required');
+ $page->fillField('Alternative text', $this->randomString());
+ $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save');
+ $assert_session->assertWaitOnAjaxRequest();
+
+ // The file should be permanent now.
+ $files = $file_storage->loadMultiple();
+ $file = array_pop($files);
+ $this->assertFalse($file->isTemporary());
+
+ // Ensure the media item was added.
+ $assert_session->pageTextNotContains('Media library');
+ $assert_session->pageTextContains($png_image->filename);
+
+ // Open the browser again to test type resolution.
+ $unlimited_button = $assert_session->elementExists('css', '.media-library-open-button[href*="field_twin_media"]');
+ $unlimited_button->click();
+ $assert_session->assertWaitOnAjaxRequest();
+ $assert_session->pageTextContains('Media library');
+ $assert_session->elementExists('css', '#drupal-modal')->clickLink('Add media');
+ $assert_session->assertWaitOnAjaxRequest();
+
+ $page->attachFileToField('Upload', $file_system->realpath($jpg_image->uri));
+ $assert_session->assertWaitOnAjaxRequest();
+
+ $assert_session->pageTextContains('Select a media type for ' . $jpg_image->filename);
+
+ // Before the type is determined, the file lives in the default upload
+ // location (temporary://).
+ $files = $file_storage->loadMultiple();
+ $file = array_pop($files);
+ $this->assertSame('temporary', $file_system->uriScheme($file->getFileUri()));
+
+ // Both the type_three and type_four media types accept jpg images.
+ $assert_session->buttonExists('Type Three');
+ $assert_session->buttonExists('Type Four')->click();
+ $assert_session->assertWaitOnAjaxRequest();
+
+ // The file should have been moved when the type was selected.
+ $files = $file_storage->loadMultiple();
+ $file = array_pop($files);
+ $this->assertSame('public://type-four-dir', $file_system->dirname($file->getFileUri()));
+ $this->assertSame($assert_session->fieldExists('Name')->getValue(), $jpg_image->filename);
+ $page->fillField('Alternative text', $this->randomString());
+
+ // The type_four media type has another optional image field.
+ $assert_session->pageTextContains('Extra Image');
+ $page->attachFileToField('Extra Image', $this->container->get('file_system')->realpath($jpg_image->uri));
+ $assert_session->assertWaitOnAjaxRequest();
+ // Ensure that the extra image was uploaded to the correct directory.
+ $files = $file_storage->loadMultiple();
+ $file = array_pop($files);
+ $this->assertSame('public://type-four-extra-dir', $file_system->dirname($file->getFileUri()));
+
+ $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save');
+ $assert_session->assertWaitOnAjaxRequest();
+
+ $assert_session->pageTextNotContains('Media library');
+ $assert_session->pageTextContains($jpg_image->filename);
+ }
+
}