From 69aa061710a2a1c6c16311cece1073e2c7523f38 Mon Sep 17 00:00:00 2001 From: Henrik Danielsson <h.danielsson@gmail.com> Date: Sat, 29 Mar 2025 21:56:40 +0100 Subject: [PATCH] Fix CKEditor plugin translations not filtered on AJAX. --- .../ckeditor5/src/Hook/Ckeditor5Hooks.php | 15 +++- .../tests/src/Unit/CKEditor5Test.php | 83 +++++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/core/modules/ckeditor5/src/Hook/Ckeditor5Hooks.php b/core/modules/ckeditor5/src/Hook/Ckeditor5Hooks.php index 85ead6ae51dd..fe93faee5c3d 100644 --- a/core/modules/ckeditor5/src/Hook/Ckeditor5Hooks.php +++ b/core/modules/ckeditor5/src/Hook/Ckeditor5Hooks.php @@ -311,13 +311,24 @@ public function jsAlter(&$javascript, AttachedAssetsInterface $assets, LanguageI // This file means CKEditor 5 translations are in use on the page. // @see locale_js_alter() $placeholder_file = 'core/assets/vendor/ckeditor5/translation.js'; + // If either the placeholder script exists, or one of the resulting language + // libraries were already loaded, keep filtering the scripts. + $filter_scripts = isset($javascript[$placeholder_file]); + if (!$filter_scripts) { + foreach ($assets->getAlreadyLoadedLibraries() as $library) { + if (str_starts_with($library, 'core/ckeditor5.translations.')) { + $filter_scripts = TRUE; + break; + } + } + } // This file is used to get a weight that will make it possible to aggregate // all translation files in a single aggregate. $ckeditor_dll_file = 'core/assets/vendor/ckeditor5/ckeditor5-dll/ckeditor5-dll.js'; - if (isset($javascript[$placeholder_file])) { + if ($filter_scripts) { // Use the placeholder file weight to set all the translations files // weights so they can be aggregated together as expected. - $default_weight = $javascript[$placeholder_file]['weight']; + $default_weight = $javascript[$placeholder_file]['weight'] ?? 0; if (isset($javascript[$ckeditor_dll_file])) { $default_weight = $javascript[$ckeditor_dll_file]['weight']; } diff --git a/core/modules/ckeditor5/tests/src/Unit/CKEditor5Test.php b/core/modules/ckeditor5/tests/src/Unit/CKEditor5Test.php index 7a202abfc2f7..ebe46f8b8d5b 100644 --- a/core/modules/ckeditor5/tests/src/Unit/CKEditor5Test.php +++ b/core/modules/ckeditor5/tests/src/Unit/CKEditor5Test.php @@ -4,7 +4,12 @@ namespace Drupal\Tests\ckeditor5\Unit; +use Drupal\ckeditor5\Hook\Ckeditor5Hooks; use Drupal\ckeditor5\Plugin\Editor\CKEditor5; +use Drupal\Core\Asset\AttachedAssets; +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Language\Language; use Drupal\Tests\ckeditor5\Traits\PrivateMethodUnitTestTrait; use Drupal\Tests\UnitTestCase; @@ -101,4 +106,82 @@ public static function providerPathsToFormNames(): array { ]; } + /** + * Test the js_alter hook alters when expected. + * + * @covers \Drupal\ckeditor5\Hook\Ckeditor5Hooks::jsAlter + */ + public function testJsAlterHook(): void { + $placeholder_file = 'core/assets/vendor/ckeditor5/translation.js'; + $hooks = new Ckeditor5Hooks(); + $assets = new AttachedAssets(); + $language = new Language([ + 'id' => 'en', + 'name' => 'English', + 'direction' => 'ltr', + ]); + $original_javascript = [ + 'keep_this' => [ + 'ckeditor5_langcode' => 'en', + ], + 'remove_this' => [ + 'ckeditor5_langcode' => 'sv', + ], + 'keep_this_too' => [], + ]; + $expected_javascript = [ + 'keep_this' => [ + 'ckeditor5_langcode' => 'en', + 'weight' => 5, + ], + 'keep_this_too' => [], + ]; + + $container = new ContainerBuilder(); + $module_handler = $this->prophesize(ModuleHandlerInterface::class); + $module_handler->getModule('locale')->willReturn(TRUE); + $container->set('module_handler', $module_handler); + \Drupal::setContainer($container); + + // First check that it filters when the placeholder script is present. + $javascript = $original_javascript + [ + $placeholder_file => [ + 'weight' => 5, + ], + ]; + $hooks->jsAlter($javascript, $assets, $language); + $this->assertEquals($expected_javascript, $javascript); + + // Next check it still filters if the placeholder script has already been + // loaded and is now excluded from the list, such as an AJAX operation + // loading a new format which uses another set of plugins. + $assets->setAlreadyLoadedLibraries([ + 'core/ckeditor5.translations.en', + ]); + $javascript = $original_javascript; + $hooks->jsAlter($javascript, $assets, $language); + // There was no placeholder to get the weight from. + $expected_javascript['keep_this']['weight'] = 0; + $this->assertEquals($expected_javascript, $javascript); + } + +} + +namespace Drupal\ckeditor5\Hook; + +if (!function_exists('_ckeditor5_get_langcode_mapping')) { + + /** + * Mock language mapping between Drupal and CKEditor 5. + * + * @param string|bool $lang + * The Drupal langcode to match. + * + * @return array|mixed|string + * The associated CKEditor 5 langcode. + */ + function _ckeditor5_get_langcode_mapping($lang = FALSE) { + return $lang ?: []; + } + } -- GitLab