ckeditor5 1.26.1 → 1.27.0

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: b30c6cdd98e034209f4dd07ffa70d5a209c207fc1f7a7b37dfd58192a12ac4bc
4
- data.tar.gz: e36f7f055fc52af917e2b146653879172a840af29e16665a650c6331092a18a7
3
+ metadata.gz: 93b0f87e014924cf2ba04dc4d8ce96afef84152c4c8fc7bdebf5a736db864b95
4
+ data.tar.gz: 02b97648d5c94907741382795721e5944ecc0752c3b2792cfe0c7455c482f81f
5
5
  SHA512:
6
- metadata.gz: de3f06d82c4dedc97d34e3082a2f1aaf13323b9fb15ed0bc68d126fa4f63890234206e5fc52528e27332937d9330fc70440b687cc91a7facfe6f8a7b04271836
7
- data.tar.gz: 26c4eeb0617420bd283841c0bd4bd77a3516eef5287e59a7388591bc6f8538838c7abba67ccc20fc4a32db5662daa8c168954767eb158a96a4cfcc626ed36310
6
+ metadata.gz: 992f3a903d5bd123e91b572f0d0154c42044f90768264fe07a5c61d343431921ed3a45515f8f74ad48a68a0870876e9f73184cdc14266f4c0e43a4f393306a93
7
+ data.tar.gz: 64a1063477787141603fd850b6de704223c15b8dd6dbedcd713ea4a5ae69fb1ebf630ba1eaef9fc245a95272f4b32b40618065e04e0c69d72b8536677ef107bd
data/README.md CHANGED
@@ -8,7 +8,10 @@
8
8
  ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/mati365/ckeditor5-rails?style=flat-square)
9
9
  [![GitHub issues](https://img.shields.io/github/issues/mati365/ckeditor5-rails?style=flat-square)](https://github.com/Mati365/ckeditor5-rails/issues)
10
10
 
11
- Unofficial CKEditor 5 Ruby on Rails integration gem. Provides seamless integration of CKEditor 5 with Rails applications through web components and helper methods.
11
+ CKEditor 5 Ruby on Rails integration gem. Provides seamless integration of CKEditor 5 with Rails applications through web components and helper methods. This gem supports various editor types, including classic, inline, balloon, and decoupled editors. It also includes support for custom plugins, translations, and configuration options.
12
+
13
+ > [!IMPORTANT]
14
+ > This gem is unofficial and not maintained by CKSource. For official CKEditor 5 documentation, visit [ckeditor.com](https://ckeditor.com/docs/ckeditor5/latest/). If you encounter any issues in integration, please report them on the [GitHub repository](https://github.com/Mati365/ckeditor5-rails/issues).
12
15
 
13
16
  <p align="center">
14
17
  <img src="docs/intro-classic-editor.png" alt="CKEditor 5 Classic Editor in Ruby on Rails application">
@@ -22,6 +25,10 @@ Add this line to your application's Gemfile:
22
25
  gem 'ckeditor5'
23
26
  ```
24
27
 
28
+ > [!NOTE]
29
+ > This gem uses importmaps and does not require Webpacker or any other JavaScript bundler. It's compatible with Rails 6.0+ and `importmap-rails` gem.
30
+ > While installation is simplified, it's recommended to check if jsdelivr or unpkg CDN is accessible in your environment, otherwise, you may need to configure a custom CDN (or use a commercial one).
31
+
25
32
  In your layout:
26
33
 
27
34
  ```erb
@@ -80,7 +87,7 @@ CKEditor5::Rails.configure do
80
87
 
81
88
  # Optionally, you can specify version of CKEditor 5 to use.
82
89
  # If it's not specified the default version specified in the gem will be used.
83
- # version '44.1.0'
90
+ # version '44.2.0'
84
91
 
85
92
  # Upload images to the server using the simple upload adapter, instead of Base64 encoding.
86
93
  # simple_upload_adapter
@@ -142,7 +149,9 @@ For extending CKEditor's functionality, refer to the [plugins directory](https:/
142
149
  - [`simple_upload_adapter(url)` method](#simple_upload_adapterurl-method)
143
150
  - [`special_characters(&block)` method](#special_charactersblock-method)
144
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)
145
153
  - [Controller / View helpers 📦](#controller--view-helpers-)
154
+ - [`ckeditor5_translation_ref(key)` method](#ckeditor5_translation_refkey-method)
146
155
  - [`ckeditor5_element_ref(selector)` method](#ckeditor5_element_refselector-method)
147
156
  - [`ckeditor5_preset(name = nil, &block)` method](#ckeditor5_presetname--nil-block-method)
148
157
  - [Including CKEditor 5 assets 📦](#including-ckeditor-5-assets-)
@@ -201,7 +210,7 @@ You can create your own by defining it in the `config/initializers/ckeditor5.rb`
201
210
 
202
211
  CKEditor5::Rails.configure do
203
212
  # It's possible to override the default preset right in the initializer.
204
- version '44.1.0'
213
+ version '44.2.0'
205
214
 
206
215
  # New presets inherit properties from the default preset defined in the initializer.
207
216
  # In this example, the custom preset inherits everything from default but disables the menubar:
@@ -211,7 +220,7 @@ CKEditor5::Rails.configure do
211
220
 
212
221
  # In order to define preset from scratch, you can use the `inherit: false` option.
213
222
  presets.define :blank_preset, inherit: false do
214
- version '44.1.0'
223
+ version '44.2.0'
215
224
 
216
225
  # It tells the integration to fetch the newest security patches and bug fixes.
217
226
  # It may be disabled, but it's highly recommended to keep it enabled to avoid
@@ -333,7 +342,7 @@ Defines the version of CKEditor 5 to be used. The example below shows how to set
333
342
  CKEditor5::Rails.configure do
334
343
  # ... other configuration
335
344
 
336
- version '44.1.0'
345
+ version '44.2.0'
337
346
  end
338
347
  ```
339
348
 
@@ -345,7 +354,7 @@ In order to disable default patches, you can pass the `apply_patches: false` key
345
354
  CKEditor5::Rails.configure do
346
355
  # ... other configuration
347
356
 
348
- version '44.1.0', apply_patches: false
357
+ version '44.2.0', apply_patches: false
349
358
  end
350
359
  ```
351
360
 
@@ -1190,8 +1199,71 @@ For more info about the WProofreader plugin, check the [official documentation](
1190
1199
 
1191
1200
  </details>
1192
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
+
1193
1235
  ### Controller / View helpers 📦
1194
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
+
1195
1267
  #### `ckeditor5_element_ref(selector)` method
1196
1268
 
1197
1269
  <details>
@@ -1229,7 +1301,7 @@ It may be useful when you want to define a preset based on the current user or r
1229
1301
  class ApplicationController < ActionController::Base
1230
1302
  def show
1231
1303
  @preset = ckeditor5_preset do
1232
- version '44.1.0'
1304
+ version '44.2.0'
1233
1305
 
1234
1306
  toolbar :sourceEditing, :|, :bold, :italic, :underline, :strikethrough,
1235
1307
  :subscript, :superscript, :removeFormat, :|, :bulletedList, :numberedList,
@@ -1264,7 +1336,7 @@ If you want to override the preset defined in the initializer, you can search fo
1264
1336
  class ApplicationController < ActionController::Base
1265
1337
  def show
1266
1338
  @preset = ckeditor5_preset(:default).override do
1267
- version '44.1.0'
1339
+ version '44.2.0'
1268
1340
 
1269
1341
  toolbar :sourceEditing, :|, :bold, :italic, :underline, :strikethrough,
1270
1342
  :subscript, :superscript, :removeFormat, :|, :bulletedList, :numberedList,
@@ -1437,7 +1509,7 @@ In that scenario it's recommended to add `gpl` method to the initializer along w
1437
1509
 
1438
1510
  CKEditor5::Rails.configure do
1439
1511
  gpl
1440
- version '44.1.0'
1512
+ version '44.2.0'
1441
1513
  end
1442
1514
  ```
1443
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.
@@ -50,10 +64,7 @@ module CKEditor5::Rails::Editor::Helpers
50
64
 
51
65
  raise ArgumentError, 'Configuration block is required for preset definition' unless block_given?
52
66
 
53
- CKEditor5::Rails::Presets::PresetBuilder.new(
54
- disallow_inline_plugins: true,
55
- &block
56
- )
67
+ CKEditor5::Rails::Presets::PresetBuilder.new(&block)
57
68
  end
58
69
  end
59
70
  end
@@ -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'
@@ -9,13 +9,12 @@ module CKEditor5::Rails
9
9
  module PluginMethods
10
10
  extend ActiveSupport::Concern
11
11
 
12
- class DisallowedInlinePluginError < ArgumentError; end
13
12
  class MissingInlinePluginError < StandardError; end
14
13
  class UnsupportedESModuleError < StandardError; end
15
14
  class InvalidPatchPluginError < ArgumentError; end
16
15
 
17
16
  included do
18
- attr_reader :disallow_inline_plugins, :disallow_inline_plugin_compression
17
+ attr_reader :disallow_inline_plugin_compression
19
18
  end
20
19
 
21
20
  # Registers an external plugin loaded from a URL
@@ -124,28 +123,11 @@ module CKEditor5::Rails
124
123
 
125
124
  private
126
125
 
127
- # Check if the plugin looks like an inline plugin
128
- # @param plugin [Editor::PropsBasePlugin] Plugin instance
129
- # @return [Boolean] True if the plugin is an inline plugin
130
- def looks_like_unsafe_inline_plugin?(plugin)
131
- plugin.respond_to?(:code) &&
132
- plugin.code.present? &&
133
- !plugin.is_a?(CKEditor5::Rails::Editor::PropsPatchPlugin)
134
- end
135
-
136
126
  # Register a plugin in the editor configuration.
137
127
  #
138
- # It will raise an error if inline plugins are not allowed and the plugin is an inline plugin.
139
- # Most likely, this is being thrown when you use inline_plugin definition in a place where
140
- # it's not allowed (e.g. in a preset definition placed in controller).
141
- #
142
128
  # @param plugin_obj [Editor::PropsBasePlugin] Plugin instance to register
143
129
  # @return [Editor::PropsBasePlugin] The registered plugin
144
130
  def register_plugin(plugin_obj)
145
- if disallow_inline_plugins && looks_like_unsafe_inline_plugin?(plugin_obj)
146
- raise DisallowedInlinePluginError, 'Inline plugins are not allowed here.'
147
- end
148
-
149
131
  config[:plugins] ||= []
150
132
  config[:plugins] << plugin_obj
151
133
  plugin_obj
@@ -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
@@ -17,8 +17,7 @@ module CKEditor5::Rails
17
17
  # gpl
18
18
  # type :classic
19
19
  # end
20
- def initialize(disallow_inline_plugins: false, &block)
21
- @disallow_inline_plugins = disallow_inline_plugins
20
+ def initialize(&block)
22
21
  @version = nil
23
22
  @premium = false
24
23
  @cdn = :jsdelivr
@@ -28,6 +27,7 @@ module CKEditor5::Rails
28
27
  @ckbox = nil
29
28
  @editable_height = nil
30
29
  @automatic_upgrades = false
30
+ @custom_translations = {}
31
31
  @config = {
32
32
  plugins: [],
33
33
  toolbar: []
@@ -36,6 +36,12 @@ module CKEditor5::Rails
36
36
  instance_eval(&block) if block_given?
37
37
  end
38
38
 
39
+ def deconstruct_keys(keys)
40
+ keys.index_with do |key|
41
+ public_send(key)
42
+ end
43
+ end
44
+
39
45
  # @example Copy preset and modify it
40
46
  # original = PresetBuilder.new
41
47
  # copied = original.initialize_copy(original)
@@ -44,6 +50,7 @@ module CKEditor5::Rails
44
50
 
45
51
  @translations = source.translations.dup
46
52
  @ckbox = source.ckbox.dup if source.ckbox
53
+ @custom_translations = source.custom_translations.deep_dup
47
54
  @config = {
48
55
  plugins: source.config[:plugins].map(&:dup),
49
56
  toolbar: deep_copy_toolbar(source.config[:toolbar])
@@ -64,12 +71,6 @@ module CKEditor5::Rails
64
71
  license_key == 'GPL'
65
72
  end
66
73
 
67
- def deconstruct_keys(keys)
68
- keys.index_with do |key|
69
- public_send(key)
70
- end
71
- end
72
-
73
74
  # Create a new preset by overriding current configuration
74
75
  # @example Override existing preset
75
76
  # preset.override do
@@ -200,7 +201,7 @@ module CKEditor5::Rails
200
201
  # Apply integration patches for the current version
201
202
  # @return [void]
202
203
  def apply_integration_patches
203
- patch_plugin Plugins::Patches::FixColorPickerRaceCondition.new
204
+ patch_plugin(Plugins::Patches::FixColorPickerRaceCondition.new)
204
205
  end
205
206
 
206
207
  # Enable or disable automatic version upgrades
@@ -334,6 +335,37 @@ module CKEditor5::Rails
334
335
  config[:language].present?
335
336
  end
336
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
+
337
369
  # Configure editor language
338
370
  # @param ui [Symbol, nil] UI language code
339
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.1'
5
+ VERSION = '1.27.0'
6
6
 
7
- DEFAULT_CKEDITOR_VERSION = '44.1.0'
7
+ DEFAULT_CKEDITOR_VERSION = '44.2.0'
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') }
@@ -38,23 +38,6 @@ RSpec.describe CKEditor5::Rails::Editor::Helpers::Config do
38
38
  it 'yields the block to PresetBuilder' do
39
39
  expect { |b| helper.ckeditor5_preset(&b) }.to yield_control
40
40
  end
41
-
42
- it 'does not allow inline plugins definition' do
43
- expect do
44
- helper.ckeditor5_preset do
45
- inline_plugin :CustomPlugin, <<~JS
46
- const { Plugin } = await import( 'ckeditor5' );
47
-
48
- return class CustomPlugin extends Plugin {
49
- static get pluginName() { return 'CustomPlugin'; }
50
- }
51
- JS
52
- end
53
- end.to raise_error(
54
- CKEditor5::Rails::Presets::Concerns::PluginMethods::DisallowedInlinePluginError,
55
- 'Inline plugins are not allowed here.'
56
- )
57
- end
58
41
  end
59
42
 
60
43
  context 'when neither name nor block is provided' do
@@ -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.1
4
+ version: 1.27.0
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-10 00:00:00.000000000 Z
12
+ date: 2025-02-14 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