Issue #3280279 by AleexGreen, Wim Leers, sandeepraib, kim.pepper, smustgrave, alexpott, quietone, pradhumanjain2311, bruno.bicudo, longwave, claudiu.cristea, larowlan: Allow sites to programmatically opt in to accept more image type uploads in CKEditor 5: TIFF, SVG…

(cherry picked from commit 8f95f51a84)
merge-requests/7849/head
Alex Pott 2024-04-16 14:23:15 +01:00
parent 5535002dbc
commit e1e8d87df6
No known key found for this signature in database
GPG Key ID: BDA67E7EE836E5CE
7 changed files with 100 additions and 9 deletions

View File

@ -242,6 +242,7 @@ use Drupal\ckeditor5\Plugin\CKEditor5PluginDefinition;
* @see \Drupal\ckeditor5\Plugin\CKEditor5PluginManager
*/
function hook_ckeditor5_plugin_info_alter(array &$plugin_definitions): void {
// Add a link decorator to the link plugin.
assert($plugin_definitions['ckeditor5_link'] instanceof CKEditor5PluginDefinition);
$link_plugin_definition = $plugin_definitions['ckeditor5_link']->toArray();
$link_plugin_definition['ckeditor5']['config']['link']['decorators'][] = [
@ -252,6 +253,16 @@ function hook_ckeditor5_plugin_info_alter(array &$plugin_definitions): void {
],
];
$plugin_definitions['ckeditor5_link'] = new CKEditor5PluginDefinition($link_plugin_definition);
// Add a custom file type to the image upload plugin. Note that 'tiff' below
// should be an IANA image media type Name, with the "image/" prefix omitted.
// In other words: a subtype of type image.
// @see https://www.iana.org/assignments/media-types/media-types.xhtml#image
// @see https://ckeditor.com/docs/ckeditor5/latest/api/module_image_imageconfig-ImageUploadConfig.html#member-types
assert($plugin_definitions['ckeditor5_imageUpload'] instanceof CKEditor5PluginDefinition);
$image_upload_plugin_definition = $plugin_definitions['ckeditor5_imageUpload']->toArray();
$image_upload_plugin_definition['ckeditor5']['config']['image']['upload']['types'][] = 'tiff';
$plugin_definitions['ckeditor5_imageUpload'] = new CKEditor5PluginDefinition($image_upload_plugin_definition);
}
/**

View File

@ -588,6 +588,8 @@ ckeditor5_imageUpload:
config:
image:
upload:
# The strings in this array should be IANA media type Names, without the "image/" prefix. So: image subtypes.
# https://www.iana.org/assignments/media-types/media-types.xhtml#image
types: ["jpeg", "png", "gif"]
drupal:
label: Image Upload

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Drupal\ckeditor5\Controller;
use Drupal\ckeditor5\Plugin\CKEditor5PluginManagerInterface;
use Drupal\Component\Utility\Bytes;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Environment;
@ -25,6 +26,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
use Symfony\Component\Lock\Exception\LockAcquiringException;
use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\Mime\MimeTypeGuesserInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
@ -38,6 +40,10 @@ class CKEditor5ImageController extends ControllerBase {
/**
* The default allowed image extensions.
*
* @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0 without replacement.
*
* @see https://www.drupal.org/node/3384728
*/
const DEFAULT_IMAGE_EXTENSIONS = 'gif png jpg jpeg';
@ -56,23 +62,35 @@ class CKEditor5ImageController extends ControllerBase {
*/
protected FileUploadHandler $fileUploadHandler;
/**
* The CKEditor 5 plugin manager.
*/
protected CKEditor5PluginManagerInterface $pluginManager;
/**
* Constructs a new CKEditor5ImageController.
*
* @param \Drupal\Core\File\FileSystemInterface $fileSystem
* The file upload handler.
* The file system service.
* @param \Drupal\Core\Session\AccountInterface|\Drupal\file\Upload\FileUploadHandler $fileUploadHandler
* The currently authenticated user.
* The file upload handler.
* @param \Symfony\Component\Mime\MimeTypeGuesserInterface|\Drupal\Core\Lock\LockBackendInterface $mime_type_guesser
* The MIME type guesser.
* @param \Drupal\Core\Lock\LockBackendInterface|null $lock
* The lock service.
* @param \Drupal\Core\Lock\LockBackendInterface|\Drupal\ckeditor5\Plugin\CKEditor5PluginManagerInterface $pluginManager
* The CKEditor 5 plugin manager.
* @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface|null $event_dispatcher
* The event dispatcher.
* @param \Drupal\file\Validation\FileValidatorInterface|null $file_validator
* The file validator.
*/
public function __construct(FileSystemInterface $fileSystem, AccountInterface | FileUploadHandler $fileUploadHandler, MimeTypeGuesserInterface | LockBackendInterface $mime_type_guesser, LockBackendInterface $lock = NULL, EventDispatcherInterface $event_dispatcher = NULL, FileValidatorInterface $file_validator = NULL) {
public function __construct(
FileSystemInterface $fileSystem,
AccountInterface | FileUploadHandler $fileUploadHandler,
MimeTypeGuesserInterface | LockBackendInterface $mime_type_guesser,
LockBackendInterface | CKEditor5PluginManagerInterface $pluginManager,
EventDispatcherInterface $event_dispatcher = NULL,
FileValidatorInterface $file_validator = NULL
) {
$this->fileSystem = $fileSystem;
if ($fileUploadHandler instanceof AccountInterface) {
@trigger_error('Calling ' . __METHOD__ . '() with the $current_user argument is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3388990', E_USER_DEPRECATED);
@ -84,9 +102,11 @@ class CKEditor5ImageController extends ControllerBase {
$mime_type_guesser = \Drupal::service('lock');
}
$this->lock = $mime_type_guesser;
if ($lock) {
@trigger_error('Calling ' . __METHOD__ . '() with the $lock argument in position 4 is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3388990', E_USER_DEPRECATED);
if ($pluginManager instanceof LockBackendInterface) {
@trigger_error('Calling ' . __METHOD__ . '() with the $lock argument in position 4 is deprecated in drupal:10.3.0 and is required in drupal:11.0.0. See https://www.drupal.org/node/3384728', E_USER_DEPRECATED);
$pluginManager = \Drupal::service('plugin.manager.ckeditor5.plugin');
}
$this->pluginManager = $pluginManager;
if ($event_dispatcher) {
@trigger_error('Calling ' . __METHOD__ . '() with the $event_dispatcher argument is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3388990', E_USER_DEPRECATED);
}
@ -102,7 +122,8 @@ class CKEditor5ImageController extends ControllerBase {
return new static(
$container->get('file_system'),
$container->get('file.upload_handler'),
$container->get('lock')
$container->get('lock'),
$container->get('plugin.manager.ckeditor5.plugin')
);
}
@ -183,9 +204,17 @@ class CKEditor5ImageController extends ControllerBase {
if (!empty($settings['max_dimensions']['width']) || !empty($settings['max_dimensions']['height'])) {
$max_dimensions = $settings['max_dimensions']['width'] . 'x' . $settings['max_dimensions']['height'];
}
$mimetypes = MimeTypes::getDefault();
$imageUploadPlugin = $this->pluginManager->getDefinition('ckeditor5_imageUpload')->toArray();
$allowed_extensions = [];
foreach ($imageUploadPlugin['ckeditor5']['config']['image']['upload']['types'] as $mime_type) {
$allowed_extensions = array_merge($allowed_extensions, $mimetypes->getExtensions('image/' . $mime_type));
}
return [
'FileExtension' => [
'extensions' => self::DEFAULT_IMAGE_EXTENSIONS,
'extensions' => implode(' ', $allowed_extensions),
],
'FileSizeLimit' => [
'fileLimit' => $max_filesize,

View File

@ -0,0 +1 @@
<svg fill="none" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ffd23f"><path d="M6.5 1h3v9h-3z"/><circle cx="8" cy="13.5" r="1.5"/></g></svg>

After

Width:  |  Height:  |  Size: 164 B

View File

@ -0,0 +1,6 @@
name: CKEditor 5 Module Allowed Image
type: module
description: Alters the allowed image types.
package: Testing
dependencies:
- drupal:ckeditor5

View File

@ -0,0 +1,22 @@
<?php
/**
* @file
* A module to add a custom image type for CKEditor 5.
*/
use Drupal\ckeditor5\Plugin\CKEditor5PluginDefinition;
/**
* Implements hook_ckeditor5_plugin_info_alter().
*/
function ckeditor5_test_module_allowed_image_ckeditor5_plugin_info_alter(array &$plugin_definitions): void {
// Add a custom file type to the image upload plugin. Note that 'svg+xml'
// below should be an IANA image media type Name, with the "image/" prefix
// omitted. In other words: a subtype of type image.
// @see https://www.iana.org/assignments/media-types/media-types.xhtml#image
// @see https://ckeditor.com/docs/ckeditor5/latest/api/module_image_imageconfig-ImageUploadConfig.html#member-types
$image_upload_plugin_definition = $plugin_definitions['ckeditor5_imageUpload']->toArray();
$image_upload_plugin_definition['ckeditor5']['config']['image']['upload']['types'][] = 'svg+xml';
$plugin_definitions['ckeditor5_imageUpload'] = new CKEditor5PluginDefinition($image_upload_plugin_definition);
}

View File

@ -160,4 +160,24 @@ class ImageTest extends ImageTestBase {
$assert_session->elementExists('css', '[data-drupal-selector="edit-editor-settings-plugins-ckeditor5-image"]');
}
/**
* Tests that it's possible to upload SVG image, with the test module enabled.
*/
public function testCanUploadSvg(): void {
$this->container->get('module_installer')
->install(['ckeditor5_test_module_allowed_image']);
$page = $this->getSession()->getPage();
$src = 'core/modules/ckeditor5/tests/fixtures/test-svg-upload.svg';
$this->drupalGet($this->host->toUrl('edit-form'));
$this->waitForEditor();
$this->assertNotEmpty($image_upload_field = $page->find('css', '.ck-file-dialog-button input[type="file"]'));
$image_upload_field->attachFile($this->container->get('file_system')->realpath($src));
// Wait for the image to be uploaded and rendered by CKEditor 5.
$this->assertNotEmpty($this->assertSession()->waitForElementVisible('css', '.ck-widget.image-inline > img[src$="test-svg-upload.svg"]'));
}
}