Verified Commit 9152c94f authored by Dave Long's avatar Dave Long
Browse files

fix: #3465020 CKEditor 5 overrides dialogSettings objects provided by CKEditor plugins

By: kevinquillen
By: dieterholvoet
By: smustgrave
By: scott_euser
By: nitinkumar_7
parent cfcf382a
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -625,9 +625,13 @@
        : [];
      classes.push('ui-dialog--narrow');
      dialogSettings.classes['ui-dialog'] = classes.join(' ');
      if (typeof dialogSettings.autoResize === 'undefined') {
        dialogSettings.autoResize =
          window.matchMedia('(min-width: 600px)').matches;
      }
      if (typeof dialogSettings.width === 'undefined') {
        dialogSettings.width = 'auto';
      }

      const ckeditorAjaxDialog = Drupal.ajax({
        dialog: dialogSettings,
+100 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
use Symfony\Component\Validator\ConstraintViolationInterface;

/**
 * Tests for CKEditor 5 to ensure correct focus management in dialogs.
 * Tests for CKEditor 5 dialog behavior.
 *
 * @internal
 */
@@ -89,4 +89,103 @@ function (ConstraintViolationInterface $v): string {
    $this->assertNotEmpty($content_area->getText());
  }

  /**
   * Tests that openDialog() applies defaults only when settings are undefined.
   */
  public function testOpenDialogSettings(): void {
    FilterFormat::create([
      'format' => 'ckeditor5',
      'name' => 'CKEditor 5',
      'roles' => [RoleInterface::AUTHENTICATED_ID],
    ])->save();
    Editor::create([
      'format' => 'ckeditor5',
      'editor' => 'ckeditor5',
      'image_upload' => ['status' => FALSE],
      'settings' => [
        'toolbar' => ['items' => ['link']],
      ],
    ])->save();
    $this->assertSame([], array_map(
      function (ConstraintViolationInterface $v): string {
        return (string) $v->getMessage();
      },
      iterator_to_array(CKEditor5::validatePair(
        Editor::load('ckeditor5'),
        FilterFormat::load('ckeditor5')
      ))
    ));

    $this->drupalGet('/node/add/page');
    $this->waitForEditor();

    // When neither width nor autoResize is set, defaults should be applied.
    $result = $this->getSession()->evaluateScript(<<<JS
      (function() {
        let captured = null;
        const originalAjax = Drupal.ajax;
        Drupal.ajax = function(settings) { captured = settings; return { execute: function() {} }; };
        Drupal.ckeditor5.openDialog('/test', function() {}, {});
        Drupal.ajax = originalAjax;
        return { width: captured.dialog.width, autoResizeType: typeof captured.dialog.autoResize };
      })()
    JS);
    $this->assertSame('auto', $result['width']);
    $this->assertSame('boolean', $result['autoResizeType']);

    // A pre-defined width must not be overwritten by the 'auto' default.
    $result = $this->getSession()->evaluateScript(<<<JS
      (function() {
        let captured = null;
        const originalAjax = Drupal.ajax;
        Drupal.ajax = function(settings) { captured = settings; return { execute: function() {} }; };
        Drupal.ckeditor5.openDialog('/test', function() {}, { width: '500px' });
        Drupal.ajax = originalAjax;
        return captured.dialog.width;
      })()
    JS);
    $this->assertSame('500px', $result);

    // A pre-defined autoResize: false must not be overwritten.
    $result = $this->getSession()->evaluateScript(<<<JS
      (function() {
        let captured = null;
        const originalAjax = Drupal.ajax;
        Drupal.ajax = function(settings) { captured = settings; return { execute: function() {} }; };
        Drupal.ckeditor5.openDialog('/test', function() {}, { autoResize: false });
        Drupal.ajax = originalAjax;
        return captured.dialog.autoResize;
      })()
    JS);
    $this->assertFalse($result);

    // A pre-defined autoResize: true must not be overwritten.
    $result = $this->getSession()->evaluateScript(<<<JS
      (function() {
        let captured = null;
        const originalAjax = Drupal.ajax;
        Drupal.ajax = function(settings) { captured = settings; return { execute: function() {} }; };
        Drupal.ckeditor5.openDialog('/test', function() {}, { autoResize: true });
        Drupal.ajax = originalAjax;
        return captured.dialog.autoResize;
      })()
    JS);
    $this->assertTrue($result);

    // The ui-dialog--narrow class must always be appended, even alongside
    // custom existing classes.
    $result = $this->getSession()->evaluateScript(<<<JS
      (function() {
        let captured = null;
        const originalAjax = Drupal.ajax;
        Drupal.ajax = function(settings) { captured = settings; return { execute: function() {} }; };
        Drupal.ckeditor5.openDialog('/test', function() {}, { classes: { 'ui-dialog': 'my-custom-class' } });
        Drupal.ajax = originalAjax;
        return captured.dialog.classes['ui-dialog'];
      })()
    JS);
    $this->assertStringContainsString('ui-dialog--narrow', $result);
    $this->assertStringContainsString('my-custom-class', $result);
  }

}