ckeditor5 1.26.2 → 1.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e46c611bc11950481442cb335ae063943043937c9792b6eeedd731e030cdf1c
4
- data.tar.gz: d16b561470173168c325457a00f5e83d5ca8689b0644f0d96533c05b7075193f
3
+ metadata.gz: 76e2b293ef722fde79ed1df5f4c13047252454d617854f92d7df98f33e9702c7
4
+ data.tar.gz: dbfef27c1c1458cdd8f795ef7569966f5aea6114609c7131b12891a341303c07
5
5
  SHA512:
6
- metadata.gz: 6769430ee90f270077c474bf1999e7d5fc4d2ec5c62918063e6503c39956e63a9f0bfb948de3dd376bc2bcb7212fc505a61e94cf04e46a1c2e85867d8e037e9a
7
- data.tar.gz: 93071afc776e615781cc9ff845b631bc823653f229ee9dbba22ccc2f9e9b2c5b9813c4cfaf6d672dfc9764a8db6d205631cf992b2d94a16fe8aba9df230681ad
6
+ metadata.gz: 074a2a67aa0e4f5d4b88e0a1697de6a3b3231af39fa86f4c7e07452411bb40a98004124c74f517cc503aea01a8ece1ead7c96e8f10944dd1e5c9eb850e057e7e
7
+ data.tar.gz: 73932b25cfe907f7cca5a6ecaeed667cf97249a86ae861937d5d0ed22bef9a48a15623c2ea4da144e51420c8bbcbb8c7441fe2e5dbd8ca39935296ca1b032554
data/README.md CHANGED
@@ -87,7 +87,7 @@ CKEditor5::Rails.configure do
87
87
 
88
88
  # Optionally, you can specify version of CKEditor 5 to use.
89
89
  # If it's not specified the default version specified in the gem will be used.
90
- # version '44.2.0'
90
+ # version '44.2.1'
91
91
 
92
92
  # Upload images to the server using the simple upload adapter, instead of Base64 encoding.
93
93
  # simple_upload_adapter
@@ -149,7 +149,9 @@ For extending CKEditor's functionality, refer to the [plugins directory](https:/
149
149
  - [`simple_upload_adapter(url)` method](#simple_upload_adapterurl-method)
150
150
  - [`special_characters(&block)` method](#special_charactersblock-method)
151
151
  - [`wproofreader(version: nil, cdn: nil, **config)` method](#wproofreaderversion-nil-cdn-nil-config-method)
152
+ - [`custom_translations(lang_code = nil, translations = {})` method](#custom_translationslang_code--nil-translations---method)
152
153
  - [Controller / View helpers 📦](#controller--view-helpers-)
154
+ - [`ckeditor5_translation_ref(key)` method](#ckeditor5_translation_refkey-method)
153
155
  - [`ckeditor5_element_ref(selector)` method](#ckeditor5_element_refselector-method)
154
156
  - [`ckeditor5_preset(name = nil, &block)` method](#ckeditor5_presetname--nil-block-method)
155
157
  - [Including CKEditor 5 assets 📦](#including-ckeditor-5-assets-)
@@ -208,7 +210,7 @@ You can create your own by defining it in the `config/initializers/ckeditor5.rb`
208
210
 
209
211
  CKEditor5::Rails.configure do
210
212
  # It's possible to override the default preset right in the initializer.
211
- version '44.2.0'
213
+ version '44.2.1'
212
214
 
213
215
  # New presets inherit properties from the default preset defined in the initializer.
214
216
  # In this example, the custom preset inherits everything from default but disables the menubar:
@@ -218,7 +220,7 @@ CKEditor5::Rails.configure do
218
220
 
219
221
  # In order to define preset from scratch, you can use the `inherit: false` option.
220
222
  presets.define :blank_preset, inherit: false do
221
- version '44.2.0'
223
+ version '44.2.1'
222
224
 
223
225
  # It tells the integration to fetch the newest security patches and bug fixes.
224
226
  # It may be disabled, but it's highly recommended to keep it enabled to avoid
@@ -340,7 +342,7 @@ Defines the version of CKEditor 5 to be used. The example below shows how to set
340
342
  CKEditor5::Rails.configure do
341
343
  # ... other configuration
342
344
 
343
- version '44.2.0'
345
+ version '44.2.1'
344
346
  end
345
347
  ```
346
348
 
@@ -352,7 +354,7 @@ In order to disable default patches, you can pass the `apply_patches: false` key
352
354
  CKEditor5::Rails.configure do
353
355
  # ... other configuration
354
356
 
355
- version '44.2.0', apply_patches: false
357
+ version '44.2.1', apply_patches: false
356
358
  end
357
359
  ```
358
360
 
@@ -1197,8 +1199,71 @@ For more info about the WProofreader plugin, check the [official documentation](
1197
1199
 
1198
1200
  </details>
1199
1201
 
1202
+ #### `custom_translations(lang_code = nil, translations = {})` method
1203
+
1204
+ <details>
1205
+ <summary>Define custom translations for CKEditor components and UI</summary>
1206
+
1207
+ <br />
1208
+
1209
+ Allows setting custom translations for editor components, UI elements, and headings. The translations are applied globally since they override the global translation object.
1210
+
1211
+ > [!NOTE]
1212
+ > This helper allows overriding builtin translations of the editor, but translations are overridden globally, as the CKEditor 5 uses a single translation object for all instances of the editor. It's recommended to use the `ckeditor5_translation_ref` helper to reference the translations in the configuration.
1213
+
1214
+ ```rb
1215
+ # config/initializers/ckeditor5.rb
1216
+
1217
+ CKEditor5::Rails.configure do
1218
+ # ... other configuration
1219
+
1220
+ custom_translations :en, {
1221
+ 'Heading 1': 'Your custom translation value'
1222
+ }
1223
+
1224
+ configure :heading, {
1225
+ options: [
1226
+ { model: 'heading1', title: ckeditor5_translation_ref('Heading 1') },
1227
+ # ...
1228
+ ]
1229
+ }
1230
+ end
1231
+ ```
1232
+
1233
+ </details>
1234
+
1200
1235
  ### Controller / View helpers 📦
1201
1236
 
1237
+ #### `ckeditor5_translation_ref(key)` method
1238
+
1239
+ <details>
1240
+ <summary>Defines a reference to a CKEditor 5 translation</summary>
1241
+
1242
+ <br />
1243
+
1244
+ Allows you to reference CKEditor 5 translations in the configuration. It's particularly useful when you want to use custom translations in the editor configuration.
1245
+
1246
+ ```rb
1247
+ # config/initializers/ckeditor5.rb
1248
+
1249
+ CKEditor5::Rails.configure do
1250
+ # ... other configuration
1251
+
1252
+ custom_translations :en, {
1253
+ 'Heading 1': 'Your custom translation value'
1254
+ }
1255
+
1256
+ configure :heading, {
1257
+ options: [
1258
+ { model: 'heading1', title: ckeditor5_translation_ref('Heading 1') },
1259
+ # ...
1260
+ ]
1261
+ }
1262
+ end
1263
+ ```
1264
+
1265
+ </details>
1266
+
1202
1267
  #### `ckeditor5_element_ref(selector)` method
1203
1268
 
1204
1269
  <details>
@@ -1236,7 +1301,7 @@ It may be useful when you want to define a preset based on the current user or r
1236
1301
  class ApplicationController < ActionController::Base
1237
1302
  def show
1238
1303
  @preset = ckeditor5_preset do
1239
- version '44.2.0'
1304
+ version '44.2.1'
1240
1305
 
1241
1306
  toolbar :sourceEditing, :|, :bold, :italic, :underline, :strikethrough,
1242
1307
  :subscript, :superscript, :removeFormat, :|, :bulletedList, :numberedList,
@@ -1271,7 +1336,7 @@ If you want to override the preset defined in the initializer, you can search fo
1271
1336
  class ApplicationController < ActionController::Base
1272
1337
  def show
1273
1338
  @preset = ckeditor5_preset(:default).override do
1274
- version '44.2.0'
1339
+ version '44.2.1'
1275
1340
 
1276
1341
  toolbar :sourceEditing, :|, :bold, :italic, :underline, :strikethrough,
1277
1342
  :subscript, :superscript, :removeFormat, :|, :bulletedList, :numberedList,
@@ -1444,7 +1509,7 @@ In that scenario it's recommended to add `gpl` method to the initializer along w
1444
1509
 
1445
1510
  CKEditor5::Rails.configure do
1446
1511
  gpl
1447
- version '44.2.0'
1512
+ version '44.2.1'
1448
1513
  end
1449
1514
  ```
1450
1515
 
@@ -17,6 +17,20 @@ module CKEditor5::Rails::Editor::Helpers
17
17
  { '$element': selector }
18
18
  end
19
19
 
20
+ # Creates a reference to a translation key that will be used by CKEditor.
21
+ # This helper creates a special object that CKEditor recognizes as a translation reference.
22
+ #
23
+ # @param key [String] The translation key to reference
24
+ # @return [Hash] A hash with the translation reference in CKEditor's format
25
+ #
26
+ # @example Referencing a translation in plugin configuration
27
+ # configure :toolbar, {
28
+ # placeholder: ckeditor5_translation_ref("editor.placeholder")
29
+ # }
30
+ def ckeditor5_translation_ref(key)
31
+ { '$translation': key }
32
+ end
33
+
20
34
  # Creates or retrieves a preset configuration for CKEditor.
21
35
  # When called with a name, finds and returns an existing preset.
22
36
  # When called with a block, creates a new preset with the given configuration.
@@ -78,7 +78,7 @@ module CKEditor5::Rails
78
78
  :type, :menubar, :plugins, :plugin, :inline_plugin,
79
79
  :toolbar, :block_toolbar, :balloon_toolbar,
80
80
  :language, :ckbox, :configure, :automatic_upgrades, :simple_upload_adapter,
81
- :editable_height, :wproofreader, to: :default_preset
81
+ :editable_height, :wproofreader, :custom_translations, to: :default_preset
82
82
 
83
83
  def initialize(configuration)
84
84
  @configuration = configuration
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../editor/props_inline_plugin'
4
+
5
+ module CKEditor5::Rails::Plugins
6
+ class CustomTranslationsLoader < CKEditor5::Rails::Editor::PropsInlinePlugin
7
+ def initialize(translations) # rubocop:disable Metrics/MethodLength
8
+ code = <<~JS.freeze
9
+ const { Plugin } = await import('ckeditor5');
10
+
11
+ function resolveTranslationReferences(uiLanguage, config, visited = new WeakSet()) {
12
+ if (!config || typeof config !== 'object') {
13
+ return config;
14
+ }
15
+
16
+ if (visited.has(config)) {
17
+ return config;
18
+ }
19
+
20
+ visited.add(config);
21
+
22
+ if (Array.isArray(config)) {
23
+ config.forEach((item, index) => {
24
+ config[index] = resolveTranslationReferences(uiLanguage, item, visited);
25
+ });
26
+
27
+ return config;
28
+ }
29
+
30
+ for (const key of Object.getOwnPropertyNames(config)) {
31
+ const value = config[key];
32
+
33
+ if (value && typeof value === 'object') {
34
+ if (value.$translation) {
35
+ const translationKey = value.$translation;
36
+ const translations = window.CKEDITOR_TRANSLATIONS?.[uiLanguage];
37
+
38
+ if (!translations?.dictionary[translationKey]) {
39
+ console.warn(`Translation not found for key: ${translationKey}`);
40
+ }
41
+
42
+ config[key] = translations?.dictionary[translationKey] || translationKey;
43
+ } else {
44
+ resolveTranslationReferences(uiLanguage, value, visited);
45
+ }
46
+ }
47
+ }
48
+
49
+ return config;
50
+ }
51
+
52
+ return class CustomTranslationsLoader extends Plugin {
53
+ static CUSTOM_TRANSLATIONS = Object.create( #{translations.to_json} );
54
+
55
+ static get pluginName() {
56
+ return 'CustomTranslationsLoader';
57
+ }
58
+
59
+ constructor( editor ) {
60
+ super( editor );
61
+
62
+ const { locale, config } = this.editor;
63
+
64
+ this.#extendPack();
65
+ resolveTranslationReferences(locale.uiLanguage, config._config)
66
+ }
67
+
68
+ #extendPack() {
69
+ const { uiLanguage } = this.editor.locale;
70
+ const translations = this.#translations;
71
+
72
+ if (!window.CKEDITOR_TRANSLATIONS) {
73
+ window.CKEDITOR_TRANSLATIONS = {};
74
+ }
75
+
76
+ if (!window.CKEDITOR_TRANSLATIONS[uiLanguage]) {
77
+ window.CKEDITOR_TRANSLATIONS[uiLanguage] = { dictionary: {} };
78
+ }
79
+
80
+ Object.entries(translations).forEach(([key, value]) => {
81
+ window.CKEDITOR_TRANSLATIONS[uiLanguage].dictionary[key] = value;
82
+ });
83
+ }
84
+
85
+ get #translations() {
86
+ const { uiLanguage } = this.editor.locale;
87
+
88
+ return CustomTranslationsLoader.CUSTOM_TRANSLATIONS[uiLanguage];
89
+ }
90
+ }
91
+ JS
92
+
93
+ super(:CustomTranslationsLoader, code)
94
+ compress!
95
+ end
96
+ end
97
+ end
@@ -9,6 +9,7 @@ end
9
9
  require_relative 'plugins/simple_upload_adapter'
10
10
  require_relative 'plugins/wproofreader'
11
11
  require_relative 'plugins/special_characters_bootstrap'
12
+ require_relative 'plugins/custom_translations_loader'
12
13
 
13
14
  # Plugin patches and fixes
14
15
  require_relative 'plugins/patches/fix_color_picker_race_condition'
@@ -6,7 +6,7 @@ require_relative 'special_characters_builder'
6
6
 
7
7
  module CKEditor5::Rails
8
8
  module Presets
9
- class PresetBuilder
9
+ class PresetBuilder # rubocop:disable Metrics/ClassLength
10
10
  include Editor::Helpers::Config
11
11
  include Concerns::ConfigurationMethods
12
12
  include Concerns::PluginMethods
@@ -27,6 +27,7 @@ module CKEditor5::Rails
27
27
  @ckbox = nil
28
28
  @editable_height = nil
29
29
  @automatic_upgrades = false
30
+ @custom_translations = {}
30
31
  @config = {
31
32
  plugins: [],
32
33
  toolbar: []
@@ -35,6 +36,12 @@ module CKEditor5::Rails
35
36
  instance_eval(&block) if block_given?
36
37
  end
37
38
 
39
+ def deconstruct_keys(keys)
40
+ keys.index_with do |key|
41
+ public_send(key)
42
+ end
43
+ end
44
+
38
45
  # @example Copy preset and modify it
39
46
  # original = PresetBuilder.new
40
47
  # copied = original.initialize_copy(original)
@@ -43,6 +50,7 @@ module CKEditor5::Rails
43
50
 
44
51
  @translations = source.translations.dup
45
52
  @ckbox = source.ckbox.dup if source.ckbox
53
+ @custom_translations = source.custom_translations.deep_dup
46
54
  @config = {
47
55
  plugins: source.config[:plugins].map(&:dup),
48
56
  toolbar: deep_copy_toolbar(source.config[:toolbar])
@@ -63,12 +71,6 @@ module CKEditor5::Rails
63
71
  license_key == 'GPL'
64
72
  end
65
73
 
66
- def deconstruct_keys(keys)
67
- keys.index_with do |key|
68
- public_send(key)
69
- end
70
- end
71
-
72
74
  # Create a new preset by overriding current configuration
73
75
  # @example Override existing preset
74
76
  # preset.override do
@@ -199,7 +201,7 @@ module CKEditor5::Rails
199
201
  # Apply integration patches for the current version
200
202
  # @return [void]
201
203
  def apply_integration_patches
202
- patch_plugin Plugins::Patches::FixColorPickerRaceCondition.new
204
+ patch_plugin(Plugins::Patches::FixColorPickerRaceCondition.new)
203
205
  end
204
206
 
205
207
  # Enable or disable automatic version upgrades
@@ -333,6 +335,37 @@ module CKEditor5::Rails
333
335
  config[:language].present?
334
336
  end
335
337
 
338
+ # Configure custom translations for the editor
339
+ # @param lang_code [Symbol] Language code for translations (e.g. :en, :pl)
340
+ # @param translations [Hash] A hash containing translations in format { key => translation }
341
+ # @example Add multiple translations
342
+ # custom_translations :en, {
343
+ # 'my.button': 'My Button'
344
+ # }
345
+ # custom_translations :pl, {
346
+ # 'my.button': 'Mój przycisk'
347
+ # }
348
+ # @example Use translations in configuration with ckeditor5_translation_ref
349
+ # custom_translations :en, {
350
+ # 'custom.heading': 'Custom Section'
351
+ # }
352
+ #
353
+ # configure :heading, {
354
+ # options: [
355
+ # { model: 'heading1', title: ckeditor5_translation_ref('custom.heading') }
356
+ # ]
357
+ # }
358
+ # @return [void]
359
+ def custom_translations(lang_code = nil, translations = {})
360
+ return @custom_translations if lang_code.blank?
361
+
362
+ @custom_translations[lang_code.to_sym] ||= {}
363
+ @custom_translations[lang_code.to_sym].merge!(translations)
364
+
365
+ plugins.remove(:CustomTranslationsLoader)
366
+ plugins.prepend(Plugins::CustomTranslationsLoader.new(@custom_translations))
367
+ end
368
+
336
369
  # Configure editor language
337
370
  # @param ui [Symbol, nil] UI language code
338
371
  # @param content [Symbol] Content language code
@@ -2,8 +2,8 @@
2
2
 
3
3
  module CKEditor5
4
4
  module Rails
5
- VERSION = '1.26.2'
5
+ VERSION = '1.27.1'
6
6
 
7
- DEFAULT_CKEDITOR_VERSION = '44.2.0'
7
+ DEFAULT_CKEDITOR_VERSION = '44.2.1'
8
8
  end
9
9
  end
@@ -8,7 +8,7 @@ RSpec.describe 'AJAX Form Integration', type: :feature, js: true do
8
8
  setup_form_tracking(page)
9
9
  end
10
10
 
11
- shared_examples 'an ajax form with CKEditor' do |form_testid, editor_testid, submit_testid, response_id| # rubocop:disable Metrics/BlockLength
11
+ shared_examples 'an ajax form with CKEditor' do |form_testid, editor_testid, submit_testid, response_id|
12
12
  let(:form) { find("[data-testid='#{form_testid}']") }
13
13
  let(:editor) { find("[data-testid='#{editor_testid}']") }
14
14
  let(:editable) { editor.find('.ck-editor__editable') }
@@ -44,10 +44,10 @@ RSpec.describe 'CKEditor5 Types Integration', type: :feature, js: true do
44
44
  end
45
45
  end
46
46
 
47
- shared_examples 'a multiroot editor that fires change events' do |path, editables| # rubocop:disable Metrics/BlockLength
47
+ shared_examples 'a multiroot editor that fires change events' do |path, editables|
48
48
  before { visit path }
49
49
 
50
- it 'sends properly change events with proper payload for editables' do # rubocop:disable Metrics/BlockLength
50
+ it 'sends properly change events with proper payload for editables' do
51
51
  editors = editables.map do |name|
52
52
  find("[data-testid='#{name}-editable']")
53
53
  end
@@ -151,7 +151,7 @@ RSpec.describe 'CKEditor5 Types Integration', type: :feature, js: true do
151
151
  expect(page).to have_css('.ck-toolbar', count: 1)
152
152
  end
153
153
 
154
- it 'handles dynamically added editables' do # rubocop:disable Metrics/BlockLength
154
+ it 'handles dynamically added editables' do
155
155
  # Set up event listener
156
156
  page.execute_script(<<~JS)
157
157
  window._newEditableEvents = [];
@@ -8,7 +8,7 @@ RSpec.describe 'Form Integration', type: :feature, js: true do
8
8
  setup_form_tracking(page)
9
9
  end
10
10
 
11
- shared_examples 'a form with CKEditor' do |form_testid, editor_testid, submit_testid| # rubocop:disable Metrics/BlockLength
11
+ shared_examples 'a form with CKEditor' do |form_testid, editor_testid, submit_testid|
12
12
  let(:form) { find("[data-testid='#{form_testid}']") }
13
13
  let(:editor) { find("[data-testid='#{editor_testid}']") }
14
14
  let(:editable) { editor.find('.ck-editor__editable') }
@@ -494,6 +494,61 @@ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
494
494
  end
495
495
  end
496
496
 
497
+ describe '#custom_translations' do
498
+ it 'returns empty hash when called without arguments' do
499
+ expect(builder.custom_translations).to eq({})
500
+ end
501
+
502
+ it 'stores translations for a language' do
503
+ translations = { 'my.button': 'My Button' }
504
+ builder.custom_translations(:en, translations)
505
+ expect(builder.custom_translations).to eq({ en: translations })
506
+ end
507
+
508
+ it 'merges translations for the same language' do
509
+ builder.custom_translations(:en, { 'button.one': 'One' })
510
+ builder.custom_translations(:en, { 'button.two': 'Two' })
511
+
512
+ expect(builder.custom_translations[:en]).to eq({
513
+ 'button.one': 'One',
514
+ 'button.two': 'Two'
515
+ })
516
+ end
517
+
518
+ it 'handles multiple languages' do
519
+ builder.custom_translations(:en, { 'button': 'Button' })
520
+ builder.custom_translations(:pl, { 'button': 'Przycisk' })
521
+
522
+ expect(builder.custom_translations).to eq({
523
+ en: { button: 'Button' },
524
+ pl: { button: 'Przycisk' }
525
+ })
526
+ end
527
+
528
+ it 'normalizes language codes to symbols' do
529
+ builder.custom_translations('EN', { 'button': 'Button' })
530
+ expect(builder.custom_translations.keys).to eq([:EN])
531
+ end
532
+
533
+ it 'adds and replaces CustomTranslationsLoader plugin' do
534
+ translations = { 'my.button': 'My Button' }
535
+
536
+ expect do
537
+ builder.custom_translations(:en, translations)
538
+ end.to change { builder.config[:plugins].count }.by(1)
539
+
540
+ plugin = builder.config[:plugins].first
541
+ expect(plugin).to be_a(CKEditor5::Rails::Plugins::CustomTranslationsLoader)
542
+
543
+ # Adding more translations should replace the plugin
544
+ expect do
545
+ builder.custom_translations(:pl, { 'my.button': 'Mój przycisk' })
546
+ end.not_to(change { builder.config[:plugins].count })
547
+
548
+ expect(builder.config[:plugins].first).to be_a(CKEditor5::Rails::Plugins::CustomTranslationsLoader)
549
+ end
550
+ end
551
+
497
552
  describe '#deep_copy_toolbar' do
498
553
  context 'with array toolbar' do
499
554
  it 'returns duplicated array' do
@@ -552,7 +607,7 @@ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
552
607
  expect { builder.special_characters }.not_to raise_error
553
608
  end
554
609
 
555
- it 'configures special characters with groups and items' do # rubocop:disable Metrics/BlockLength
610
+ it 'configures special characters with groups and items' do
556
611
  builder.special_characters do
557
612
  group 'Emoji', label: 'Emoticons' do
558
613
  item 'smiley', '😊'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ckeditor5
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.26.2
4
+ version: 1.27.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mateusz Bagiński
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-02-13 00:00:00.000000000 Z
12
+ date: 2025-02-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -90,6 +90,7 @@ files:
90
90
  - lib/ckeditor5/rails/hooks/importmap.rb
91
91
  - lib/ckeditor5/rails/hooks/simple_form.rb
92
92
  - lib/ckeditor5/rails/plugins.rb
93
+ - lib/ckeditor5/rails/plugins/custom_translations_loader.rb
93
94
  - lib/ckeditor5/rails/plugins/patches/fix_color_picker_race_condition.rb
94
95
  - lib/ckeditor5/rails/plugins/simple_upload_adapter.rb
95
96
  - lib/ckeditor5/rails/plugins/special_characters_bootstrap.rb