From 5be422b7900a2f9d527976a47f2cd754dc49265b Mon Sep 17 00:00:00 2001 From: Benjamin Kott <benjamin.kott@outlook.com> Date: Sat, 29 Dec 2018 12:04:22 +0100 Subject: [PATCH] [FEATURE] Introduce events to modify CKEditor configuration This patch introduces a set of PSR-14 Events to modify the CKEditor configuration. - AfterGetExternalPluginsEvent - BeforeGetExternalPluginsEvent - AfterPrepareConfigurationForEditorEvent - BeforePrepareConfigurationForEditorEvent Resolves: #88818 Releases: master Change-Id: I1f810e31274a05d52082de5e03fc530b3cee1a44 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/59304 Tested-by: TYPO3com <noreply@typo3.com> Tested-by: Georg Ringer <georg.ringer@gmail.com> Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Georg Ringer <georg.ringer@gmail.com> Reviewed-by: Benni Mack <benni@typo3.org> --- ...uceEventsToModifyCKEditorConfiguration.rst | 74 +++++++++++++++++++ .../Event/AfterGetExternalPluginsEvent.php | 54 ++++++++++++++ ...fterPrepareConfigurationForEditorEvent.php | 54 ++++++++++++++ .../Event/BeforeGetExternalPluginsEvent.php | 54 ++++++++++++++ ...forePrepareConfigurationForEditorEvent.php | 54 ++++++++++++++ .../Classes/Form/Element/RichTextElement.php | 66 +++++++++++++---- 6 files changed, 343 insertions(+), 13 deletions(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-88818-IntroduceEventsToModifyCKEditorConfiguration.rst create mode 100644 typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/AfterGetExternalPluginsEvent.php create mode 100644 typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/AfterPrepareConfigurationForEditorEvent.php create mode 100644 typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/BeforeGetExternalPluginsEvent.php create mode 100644 typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/BeforePrepareConfigurationForEditorEvent.php diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-88818-IntroduceEventsToModifyCKEditorConfiguration.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-88818-IntroduceEventsToModifyCKEditorConfiguration.rst new file mode 100644 index 000000000000..c4e207373619 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-88818-IntroduceEventsToModifyCKEditorConfiguration.rst @@ -0,0 +1,74 @@ +.. include:: ../../Includes.txt + +=================================================================== +Feature: #88818 - Introduce events to modify CKEditor configuration +=================================================================== + +See :issue:`88818` + +Description +=========== + +The following new PSR-14-based Events are introduced which allow +to modify CKEditor configuration. + +- :php:`TYPO3\CMS\RteCKEditor\Form\Element\Event\AfterGetExternalPluginsEvent` +- :php:`TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforeGetExternalPluginsEvent` +- :php:`TYPO3\CMS\RteCKEditor\Form\Element\Event\AfterPrepareConfigurationForEditorEvent` +- :php:`TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforePrepareConfigurationForEditorEvent` + +Example +======= + +An example implementation how you could extend the existing +configuration to register a new plugin: + +:file:`EXT:my_extension/Configuration/Services.yaml` + +.. code-block:: yaml + + services: + Vendor\MyExtension\EventListener\RteConfigEnhancer: + tags: + - name: event.listener + identifier: 'ext-myextension/rteConfigEnhancer' + method: 'beforeGetExternalPlugins' + event: TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforeGetExternalPluginsEvent + - name: event.listener + identifier: 'ext-myextension/rteConfigEnhancer' + method: 'beforePrepareConfiguration' + event: TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforePrepareConfigurationForEditorEvent + +:file:`EXT:my_extension/Classes/EventListener/RteConfigEnhancer.php` + +.. code-block:: php + + namespace Vendor\MyExtension\EventListener; + + use TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforeGetExternalPluginsEvent; + use TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforePrepareConfigurationForEditorEvent; + + class RteConfigEnhancer + { + public function beforeGetExternalPlugins(BeforeGetExternalPluginsEvent $event): void + { + $data = $event->getData(); + // @todo make useful decisions on fetched data + $configuration = $event->getConfiguration(); + $configuration['example_plugin'] = [ + 'resource' => 'EXT:my_extension/Resources/Public/CKEditor/Plugins/ExamplePlugin/plugin.js' + ]; + $event->setConfiguration($configuration); + } + + public function beforePrepareConfiguration(BeforePrepareConfigurationForEditorEvent $event): void + { + $data = $event->getData(); + // @todo make useful decisions on fetched data + $configuration = $event->getConfiguration(); + $configuration['extraPlugins'][] = 'example_plugin'; + $event->setConfiguration($configuration); + } + } + +.. index:: Backend, PHP-API, RTE, ext:rte_ckeditor diff --git a/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/AfterGetExternalPluginsEvent.php b/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/AfterGetExternalPluginsEvent.php new file mode 100644 index 000000000000..c1f515cf516b --- /dev/null +++ b/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/AfterGetExternalPluginsEvent.php @@ -0,0 +1,54 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\RteCKEditor\Form\Element\Event; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +/** + * This event is fired after processing external plugin configuration. + */ +final class AfterGetExternalPluginsEvent +{ + /** + * @var array + */ + private $configuration; + + /** + * @var array + */ + private $data; + + public function __construct(array $configuration, array $data) + { + $this->configuration = $configuration; + $this->data = $data; + } + + public function getData(): array + { + return $this->data; + } + + public function getConfiguration(): array + { + return $this->configuration; + } + + public function setConfiguration(array $configuration): void + { + $this->configuration = $configuration; + } +} diff --git a/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/AfterPrepareConfigurationForEditorEvent.php b/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/AfterPrepareConfigurationForEditorEvent.php new file mode 100644 index 000000000000..662e4dbc0825 --- /dev/null +++ b/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/AfterPrepareConfigurationForEditorEvent.php @@ -0,0 +1,54 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\RteCKEditor\Form\Element\Event; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +/** + * This event is fired after preparing the editor configuration. + */ +final class AfterPrepareConfigurationForEditorEvent +{ + /** + * @var array + */ + private $configuration; + + /** + * @var array + */ + private $data; + + public function __construct(array $configuration, array $data) + { + $this->configuration = $configuration; + $this->data = $data; + } + + public function getData(): array + { + return $this->data; + } + + public function getConfiguration(): array + { + return $this->configuration; + } + + public function setConfiguration(array $configuration): void + { + $this->configuration = $configuration; + } +} diff --git a/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/BeforeGetExternalPluginsEvent.php b/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/BeforeGetExternalPluginsEvent.php new file mode 100644 index 000000000000..6e4132174b59 --- /dev/null +++ b/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/BeforeGetExternalPluginsEvent.php @@ -0,0 +1,54 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\RteCKEditor\Form\Element\Event; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +/** + * This event is fired before processing external plugin configuration. + */ +final class BeforeGetExternalPluginsEvent +{ + /** + * @var array + */ + private $configuration; + + /** + * @var array + */ + private $data; + + public function __construct(array $configuration, array $data) + { + $this->configuration = $configuration; + $this->data = $data; + } + + public function getData(): array + { + return $this->data; + } + + public function getConfiguration(): array + { + return $this->configuration; + } + + public function setConfiguration(array $configuration): void + { + $this->configuration = $configuration; + } +} diff --git a/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/BeforePrepareConfigurationForEditorEvent.php b/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/BeforePrepareConfigurationForEditorEvent.php new file mode 100644 index 000000000000..25cdd07ad8db --- /dev/null +++ b/typo3/sysext/rte_ckeditor/Classes/Form/Element/Event/BeforePrepareConfigurationForEditorEvent.php @@ -0,0 +1,54 @@ +<?php +declare(strict_types = 1); + +namespace TYPO3\CMS\RteCKEditor\Form\Element\Event; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +/** + * This event is fired before starting the prepare of the editor configuration. + */ +final class BeforePrepareConfigurationForEditorEvent +{ + /** + * @var array + */ + private $configuration; + + /** + * @var array + */ + private $data; + + public function __construct(array $configuration, array $data) + { + $this->configuration = $configuration; + $this->data = $data; + } + + public function getData(): array + { + return $this->data; + } + + public function getConfiguration(): array + { + return $this->configuration; + } + + public function setConfiguration(array $configuration): void + { + $this->configuration = $configuration; + } +} diff --git a/typo3/sysext/rte_ckeditor/Classes/Form/Element/RichTextElement.php b/typo3/sysext/rte_ckeditor/Classes/Form/Element/RichTextElement.php index 4ff0a8330d4b..ef13f692a7d9 100644 --- a/typo3/sysext/rte_ckeditor/Classes/Form/Element/RichTextElement.php +++ b/typo3/sysext/rte_ckeditor/Classes/Form/Element/RichTextElement.php @@ -15,12 +15,18 @@ namespace TYPO3\CMS\RteCKEditor\Form\Element; * The TYPO3 project - inspiring people to share! */ +use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Backend\Form\Element\AbstractFormElement; +use TYPO3\CMS\Backend\Form\NodeFactory; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Localization\Locales; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\PathUtility; +use TYPO3\CMS\RteCKEditor\Form\Element\Event\AfterGetExternalPluginsEvent; +use TYPO3\CMS\RteCKEditor\Form\Element\Event\AfterPrepareConfigurationForEditorEvent; +use TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforeGetExternalPluginsEvent; +use TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforePrepareConfigurationForEditorEvent; /** * Render rich text editor in FormEngine @@ -70,6 +76,24 @@ class RichTextElement extends AbstractFormElement */ protected $rteConfiguration = []; + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + + /** + * Container objects give $nodeFactory down to other containers. + * + * @param NodeFactory $nodeFactory + * @param array $data + * @param EventDispatcherInterface|null $eventDispatcher + */ + public function __construct(NodeFactory $nodeFactory, array $data, EventDispatcherInterface $eventDispatcher = null) + { + parent::__construct($nodeFactory, $data); + $this->eventDispatcher = $eventDispatcher ?? GeneralUtility::getContainer()->get(EventDispatcherInterface::class); + } + /** * Renders the ckeditor element * @@ -232,6 +256,11 @@ class RichTextElement extends AbstractFormElement */ protected function getExtraPlugins(): array { + $externalPlugins = $this->rteConfiguration['externalPlugins'] ?? []; + $externalPlugins = $this->eventDispatcher + ->dispatch(new BeforeGetExternalPluginsEvent($externalPlugins, $this->data)) + ->getConfiguration(); + $urlParameters = [ 'P' => [ 'table' => $this->data['tableName'], @@ -244,21 +273,23 @@ class RichTextElement extends AbstractFormElement ]; $pluginConfiguration = []; - if (isset($this->rteConfiguration['externalPlugins']) && is_array($this->rteConfiguration['externalPlugins'])) { - $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); - foreach ($this->rteConfiguration['externalPlugins'] as $pluginName => $configuration) { - $pluginConfiguration[$pluginName] = [ - 'resource' => $this->resolveUrlPath($configuration['resource']) - ]; - unset($configuration['resource']); - - if ($configuration['route']) { - $configuration['routeUrl'] = (string)$uriBuilder->buildUriFromRoute($configuration['route'], $urlParameters); - } - - $pluginConfiguration[$pluginName]['config'] = $configuration; + $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); + foreach ($externalPlugins as $pluginName => $configuration) { + $pluginConfiguration[$pluginName] = [ + 'resource' => $this->resolveUrlPath($configuration['resource']) + ]; + unset($configuration['resource']); + + if ($configuration['route']) { + $configuration['routeUrl'] = (string)$uriBuilder->buildUriFromRoute($configuration['route'], $urlParameters); } + + $pluginConfiguration[$pluginName]['config'] = $configuration; } + + $pluginConfiguration = $this->eventDispatcher + ->dispatch(new AfterGetExternalPluginsEvent($pluginConfiguration, $this->data)) + ->getConfiguration(); return $pluginConfiguration; } @@ -327,6 +358,11 @@ class RichTextElement extends AbstractFormElement if (is_array($this->rteConfiguration['config'])) { $configuration = array_replace_recursive($configuration, $this->rteConfiguration['config']); } + + $configuration = $this->eventDispatcher + ->dispatch(new BeforePrepareConfigurationForEditorEvent($configuration, $this->data)) + ->getConfiguration(); + // Set the UI language of the editor if not hard-coded by the existing configuration if (empty($configuration['language'])) { $configuration['language'] = $this->getBackendUser()->uc['lang'] ?: ($this->getBackendUser()->user['lang'] ?: 'en'); @@ -349,6 +385,10 @@ class RichTextElement extends AbstractFormElement $configuration['removeButtons'] = implode(',', $configuration['removeButtons']); } + $configuration = $this->eventDispatcher + ->dispatch(new AfterPrepareConfigurationForEditorEvent($configuration, $this->data)) + ->getConfiguration(); + return $configuration; } -- GitLab