diff --git a/core/modules/media/src/Form/EditorMediaDialog.php b/core/modules/media/src/Form/EditorMediaDialog.php index 3eb9b127f0..6530d6d2fe 100644 --- a/core/modules/media/src/Form/EditorMediaDialog.php +++ b/core/modules/media/src/Form/EditorMediaDialog.php @@ -94,6 +94,13 @@ public function buildForm(array $form, FormStateInterface $form_state, EditorInt $form['#prefix'] = '
'; $form['#suffix'] = '
'; + $filter_html = $editor->getFilterFormat()->filters('filter_html'); + $allowed_attributes = []; + if ($filter_html->status) { + $restrictions = $filter_html->getHTMLRestrictions(); + $allowed_attributes = $restrictions['allowed']['drupal-media']; + } + $media = $this->entityRepository->loadEntityByUuid('media', $media_embed_element['data-entity-uuid']); if ($image_field = $this->getMediaImageSourceField($media)) { $settings = $media->{$image_field}->getItemDefinition()->getSettings(); @@ -109,34 +116,56 @@ public function buildForm(array $form, FormStateInterface $form_state, EditorInt '#parents' => ['attributes', 'alt'], '#access' => !empty($settings['alt_field']), ]; + + if (!empty($allowed_attributes)) { + if (empty($allowed_attributes['alt'])) { + $form['alt']['#access'] = FALSE; + } + } } // When Drupal core's filter_align is being used, the text editor offers the // ability to change the alignment. - if ($editor->getFilterFormat()->filters('filter_align')->status) { - $form['align'] = [ - '#title' => $this->t('Align'), - '#type' => 'radios', - '#options' => [ - 'none' => $this->t('None'), - 'left' => $this->t('Left'), - 'center' => $this->t('Center'), - 'right' => $this->t('Right'), - ], - '#default_value' => empty($media_embed_element['data-align']) ? 'none' : $media_embed_element['data-align'], - '#attributes' => ['class' => ['container-inline']], - '#parents' => ['attributes', 'data-align'], - ]; + $form['align'] = [ + '#title' => $this->t('Align'), + '#type' => 'radios', + '#options' => [ + 'none' => $this->t('None'), + 'left' => $this->t('Left'), + 'center' => $this->t('Center'), + 'right' => $this->t('Right'), + ], + '#default_value' => empty($media_embed_element['data-align']) ? 'none' : $media_embed_element['data-align'], + '#attributes' => ['class' => ['container-inline']], + '#parents' => ['attributes', 'data-align'], + '#access' => !empty($editor->getFilterFormat()->filters('filter_align')->status), + ]; + + if (!empty($allowed_attributes)) { + if (empty($allowed_attributes['data-align'])) { + $form['align']['#access'] = FALSE; + } } // When Drupal core's filter_caption is being used, the text editor offers // the ability to in-place edit the media's caption: show a toggle. - if ($editor->getFilterFormat()->filters('filter_caption')->status) { - $form['caption'] = [ - '#title' => $this->t('Caption'), - '#type' => 'checkbox', - '#default_value' => $has_caption === 'true', - '#parents' => ['hasCaption'], + $form['caption'] = [ + '#title' => $this->t('Caption'), + '#type' => 'checkbox', + '#default_value' => $has_caption === 'true', + '#parents' => ['hasCaption'], + '#access' => !empty($editor->getFilterFormat()->filters('filter_caption')->status) + ]; + + if (!empty($allowed_attributes)) { + if (empty($allowed_attributes['data-caption'])) { + $form['caption']['#access'] = FALSE; + } + } + + if ($form['alt']['#access'] === FALSE && $form['align']['#access'] === FALSE && $form['caption']['#access'] === FALSE) { + $form['no_access_notice'] = [ + '#markup' => $this->t('There is nothing to override for this media.'), ]; } diff --git a/core/modules/media/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php b/core/modules/media/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php index 84d14ca689..a4b14a63ce 100644 --- a/core/modules/media/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php +++ b/core/modules/media/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php @@ -398,9 +398,9 @@ public function testEditableCaption() { } /** - * Tests the EditorMediaDialog can set the alt attribute. + * Tests field access logic in EditorMediaDialog. */ - public function testAlt() { + public function testDialogFieldAccess() { $session = $this->getSession(); $page = $session->getPage(); $assert_session = $this->assertSession(); @@ -409,6 +409,52 @@ public function testAlt() { $this->assignNameToCkeditorIframe(); $session->switchToIFrame('ckeditor'); + // Enable `filter_html` without "alt", "data-align" or "data-caption" + // attributes added to the drupal-media tag. + $allowed_html = "
    1. "; + $filter_format = $this->container->get('entity_type.manager')->getStorage('filter_format')->load('test_format'); + $filter_format->setFilterConfig('filter_html', [ + 'status' => TRUE, + 'settings' => [ + 'allowed_html' => $allowed_html, + ], + ])->save(); + + // Test the validation of attributes in the dialog. If the alt, + // data-caption, and data-align attributes are not set on the drupal-media + // tag, the respective fields shouldn't display in the dialog. + $this->drupalGet($this->host->toUrl('edit-form')); + $this->waitForEditor(); + $this->assignNameToCkeditorIframe(); + $session->switchToIFrame('ckeditor'); + $this->assertNotEmpty($assert_session->waitForElementVisible('css', 'drupal-media', 2000)); + $page->pressButton('Edit media'); + $this->waitForMetadataDialog(); + $assert_session->fieldNotExists('attributes[alt]'); + $assert_session->fieldNotExists('attributes[align]'); + $assert_session->fieldNotExists('hasCaption'); + $assert_session->pageTextContains('There is nothing to override for this media.'); + $page->pressButton('Close'); + $session->switchToIFrame('ckeditor'); + + // Now test that adding the attributes to the allowed HTML will allow + // the fields to display in the dialog. + $allowed_html = str_replace('', '', $allowed_html); + $filter_format->setFilterConfig('filter_html', [ + 'status' => TRUE, + 'settings' => [ + 'allowed_html' => $allowed_html, + ], + ])->save(); + $this->assertNotEmpty($assert_session->waitForElementVisible('css', 'drupal-media', 2000)); + $page->pressButton('Edit media'); + $this->waitForMetadataDialog(); + $assert_session->fieldExists('attributes[alt]'); + $assert_session->fieldExists('attributes[data-align]'); + $assert_session->fieldExists('hasCaption'); + $page->pressButton('Close'); + $session->switchToIFrame('ckeditor'); + // Test that setting the media image field to not display alt field also // disables it in the dialog. FieldConfig::loadByName('media', 'image', 'field_media_image') @@ -437,6 +483,49 @@ public function testAlt() { $page->pressButton('Close'); $session->switchToIFrame('ckeditor'); + // Test that setting disabling `filter_caption` and `filter_align` disables + // the respective fields in the dialog. + $filter_format + ->setFilterConfig('filter_caption', [ + 'status' => FALSE, + ])->setFilterConfig('filter_align', [ + 'status' => FALSE, + ])->save(); + // Wait for preview. + $this->assertNotEmpty($assert_session->waitForElementVisible('css', 'drupal-media', 2000)); + $page->pressButton('Edit media'); + $this->waitForMetadataDialog(); + $assert_session->fieldNotExists('attributes[data-align]'); + $assert_session->fieldNotExists('hasCaption'); + $page->pressButton('Close'); + $session->switchToIFrame('ckeditor'); + + // Test that enabling the two filters restores the fields in the dialog. + $filter_format + ->setFilterConfig('filter_caption', [ + 'status' => TRUE, + ])->setFilterConfig('filter_align', [ + 'status' => TRUE, + ])->save(); + // Wait for preview. + $this->assertNotEmpty($assert_session->waitForElementVisible('css', 'drupal-media', 2000)); + $page->pressButton('Edit media'); + $this->waitForMetadataDialog(); + $assert_session->fieldExists('attributes[data-align]'); + $assert_session->fieldExists('hasCaption'); + } + + /** + * Tests the EditorMediaDialog can set the alt attribute. + */ + public function testAlt() { + $session = $this->getSession(); + $page = $session->getPage(); + $assert_session = $this->assertSession(); + $this->drupalGet($this->host->toUrl('edit-form')); + $this->waitForEditor(); + $this->assignNameToCkeditorIframe(); + $session->switchToIFrame('ckeditor'); // Test that the default alt attribute displays without an override. $this->assertNotEmpty($assert_session->waitForElementVisible('xpath', '//img[contains(@alt, "default alt")]')); $page->pressButton('Edit media');