Commit 1f1fb63e authored by webchick's avatar webchick
Browse files

Issue #3073535 by oknate, webchick, Wim Leers, phenaproxima, seanB,...

Issue #3073535 by oknate, webchick, Wim Leers, phenaproxima, seanB, AaronMcHale: Allow only a subset of the media library to be exposed to CKEditor
parent 4afcb5fc
......@@ -112,6 +112,12 @@ filter_settings.media_embed:
default_view_mode:
type: string
label: 'The view mode that is used by default'
allowed_media_types:
type: sequence
label: 'Media types selectable in the Media Library'
sequence:
type: string
label: 'Media type'
allowed_view_modes:
type: sequence
label: 'View modes selectable in the "Edit media" dialog'
......
......@@ -5,6 +5,7 @@
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceEntityFormatter;
use Drupal\Core\Form\FormStateInterface;
......@@ -31,6 +32,7 @@
* settings = {
* "default_view_mode" = "default",
* "allowed_view_modes" = {},
* "allowed_media_types" = {},
* },
* weight = 100,
* )
......@@ -60,6 +62,13 @@ class MediaEmbed extends FilterBase implements ContainerFactoryPluginInterface,
*/
protected $entityDisplayRepository;
/**
* The entity type bundle info service.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* The renderer.
*
......@@ -101,16 +110,19 @@ class MediaEmbed extends FilterBase implements ContainerFactoryPluginInterface,
* The entity type manager.
* @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
* The entity display repository.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info
* The entity type bundle info service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
* The logger factory.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityRepositoryInterface $entity_repository, EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository, RendererInterface $renderer, LoggerChannelFactoryInterface $logger_factory) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityRepositoryInterface $entity_repository, EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository, EntityTypeBundleInfoInterface $bundle_info, RendererInterface $renderer, LoggerChannelFactoryInterface $logger_factory) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityRepository = $entity_repository;
$this->entityTypeManager = $entity_type_manager;
$this->entityDisplayRepository = $entity_display_repository;
$this->entityTypeBundleInfo = $bundle_info;
$this->renderer = $renderer;
$this->loggerFactory = $logger_factory;
}
......@@ -126,6 +138,7 @@ public static function create(ContainerInterface $container, array $configuratio
$container->get('entity.repository'),
$container->get('entity_type.manager'),
$container->get('entity_display.repository'),
$container->get('entity_type.bundle.info'),
$container->get('renderer'),
$container->get('logger.factory')
);
......@@ -145,13 +158,26 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
'#description' => $this->t('The view mode that an embedded media item should be displayed in by default. This can be overridden using the <code>data-view-mode</code> attribute.'),
];
$bundles = $this->entityTypeBundleInfo->getBundleInfo('media');
$bundle_options = array_map(function ($item) {
return $item['label'];
}, $bundles);
$form['allowed_media_types'] = [
'#title' => $this->t('Media types selectable in the Media Library'),
'#type' => 'checkboxes',
'#options' => $bundle_options,
'#default_value' => $this->settings['allowed_media_types'],
'#description' => $this->t('If none are selected, all will be allowed.'),
'#element_validate' => [[static::class, 'validateOptions']],
];
$form['allowed_view_modes'] = [
'#title' => $this->t("View modes selectable in the 'Edit media' dialog"),
'#type' => 'checkboxes',
'#options' => $view_mode_options,
'#default_value' => $this->settings['allowed_view_modes'],
'#description' => $this->t("If two or more view modes are selected, users will be able to update the view mode that an embedded media item should be displayed in after it has been embedded. If less than two view modes are selected, media will be embedded using the default view mode and no view mode options will appear after a media item has been embedded."),
'#element_validate' => [[get_class($this), 'elementValidateAllowedViewModes']],
'#element_validate' => [[static::class, 'validateOptions']],
];
return $form;
......@@ -165,7 +191,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public static function elementValidateAllowedViewModes(array &$element, FormStateInterface $form_state) {
public static function validateOptions(array &$element, FormStateInterface $form_state) {
// Filters the #value property so only selected values appear in the
// config.
$form_state->setValueForElement($element, array_filter($element['#value']));
......
......@@ -1121,6 +1121,7 @@ public function testViewMode() {
'status' => TRUE,
'settings' => [
'default_view_mode' => 'view_mode_1',
'allowed_media_types' => [],
'allowed_view_modes' => [
'view_mode_1' => 'view_mode_1',
'view_mode_2' => 'view_mode_2',
......@@ -1175,6 +1176,7 @@ public function testViewMode() {
'status' => TRUE,
'settings' => [
'default_view_mode' => 'view_mode_1',
'allowed_media_types' => [],
'allowed_view_modes' => [
'view_mode_1' => 'view_mode_1',
],
......@@ -1199,6 +1201,7 @@ public function testViewMode() {
'status' => TRUE,
'settings' => [
'default_view_mode' => 'view_mode_1',
'allowed_media_types' => [],
'allowed_view_modes' => [
'view_mode_1' => 'view_mode_1',
'view_mode_2' => 'view_mode_2',
......
......@@ -117,6 +117,15 @@ public function getConfig(Editor $editor) {
}
$media_type_ids = $this->mediaTypeStorage->getQuery()->execute();
if ($editor->hasAssociatedFilterFormat()) {
if ($media_embed_filter = $editor->getFilterFormat()->filters()->get('media_embed')) {
// Optionally limit the allowed media types based on the MediaEmbed
// setting. If the setting is empty, do not limit the options.
if (!empty($media_embed_filter->settings['allowed_media_types'])) {
$media_type_ids = array_intersect_key($media_type_ids, $media_embed_filter->settings['allowed_media_types']);
}
}
}
if (in_array('image', $media_type_ids, TRUE)) {
// Due to a bug where the active item styling and the focus styling
......
......@@ -98,7 +98,7 @@ protected function setUp() {
]);
// Create a media type that starts with the letter a, to test tab order.
$this->createMediaType('image', ['id' => 'Arrakis', 'label' => 'Arrakis']);
$this->createMediaType('image', ['id' => 'arrakis', 'label' => 'Arrakis']);
// Create a sample media entity to be embedded.
$this->createMediaType('image', ['id' => 'image', 'label' => 'Image']);
......@@ -118,6 +118,19 @@ protected function setUp() {
]);
$this->media->save();
$arrakis_media = Media::create([
'bundle' => 'arrakis',
'name' => 'Le baron Vladimir Harkonnen',
'field_media_image' => [
[
'target_id' => 1,
'alt' => 'Il complote pour détruire le duc Leto',
'title' => 'Il complote pour détruire le duc Leto',
],
],
]);
$arrakis_media->save();
$this->drupalLogin($this->user);
}
......@@ -247,4 +260,61 @@ public function testButton() {
$this->assertEditorButtonEnabled('undo');
}
/**
* Tests the allowed media types setting on the MediaEmbed filter.
*/
public function testAllowedMediaTypes() {
$test_cases = [
'all_media_types' => [],
'only_image' => ['image' => 'image'],
'only_arrakis' => ['arrakis' => 'arrakis'],
'both_items_chedked' => [
'image' => 'image',
'arrakis' => 'arrakis',
],
];
foreach ($test_cases as $allowed_media_types) {
// Update the filter format to set the allowed media types.
FilterFormat::load('test_format')
->setFilterConfig('media_embed', [
'status' => TRUE,
'settings' => [
'default_view_mode' => 'view_mode_1',
'allowed_media_types' => $allowed_media_types,
'allowed_view_modes' => [
'view_mode_1' => 'view_mode_1',
'view_mode_2' => 'view_mode_2',
],
],
])->save();
// Now test opening the media library from the CKEditor plugin, and
// verify the expected behavior.
$this->drupalGet('/node/add/blog');
$this->waitForEditor();
$this->pressEditorButton('drupalmedialibrary');
$assert_session = $this->assertSession();
$this->assertNotEmpty($assert_session->waitForId('media-library-wrapper'));
if (empty($allowed_media_types) || count($allowed_media_types) === 2) {
$assert_session->elementExists('css', 'li.media-library-menu-image');
$assert_session->elementExists('css', 'li.media-library-menu-arrakis');
$assert_session->elementTextContains('css', '.media-library-item__name', 'Fear is the mind-killer');
}
elseif (count($allowed_media_types) === 1 && !empty($allowed_media_types['image'])) {
// No tabs should appear if there's only one media type available.
$assert_session->elementNotExists('css', 'li.media-library-menu-image');
$assert_session->elementNotExists('css', 'li.media-library-menu-arrakis');
$assert_session->elementTextContains('css', '.media-library-item__name', 'Fear is the mind-killer');
}
elseif (count($allowed_media_types) === 1 && !empty($allowed_media_types['arrakis'])) {
// No tabs should appear if there's only one media type available.
$assert_session->elementNotExists('css', 'li.media-library-menu-image');
$assert_session->elementNotExists('css', 'li.media-library-menu-arrakis');
$assert_session->elementTextContains('css', '.media-library-item__name', 'Le baron Vladimir Harkonnen');
}
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment