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 +4 -4
- data/README.md +81 -9
- data/lib/ckeditor5/rails/editor/helpers/config_helpers.rb +15 -4
- data/lib/ckeditor5/rails/engine.rb +1 -1
- data/lib/ckeditor5/rails/plugins/custom_translations_loader.rb +97 -0
- data/lib/ckeditor5/rails/plugins.rb +1 -0
- data/lib/ckeditor5/rails/presets/concerns/plugin_methods.rb +1 -19
- data/lib/ckeditor5/rails/presets/preset_builder.rb +42 -10
- data/lib/ckeditor5/rails/version.rb +2 -2
- data/spec/e2e/features/ajax_form_integration_spec.rb +1 -1
- data/spec/e2e/features/editor_types_spec.rb +3 -3
- data/spec/e2e/features/form_integration_spec.rb +1 -1
- data/spec/lib/ckeditor5/rails/editor/helpers/config_helpers_spec.rb +0 -17
- data/spec/lib/ckeditor5/rails/presets/preset_builder_spec.rb +56 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93b0f87e014924cf2ba04dc4d8ce96afef84152c4c8fc7bdebf5a736db864b95
|
4
|
+
data.tar.gz: 02b97648d5c94907741382795721e5944ecc0752c3b2792cfe0c7455c482f81f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 992f3a903d5bd123e91b572f0d0154c42044f90768264fe07a5c61d343431921ed3a45515f8f74ad48a68a0870876e9f73184cdc14266f4c0e43a4f393306a93
|
7
|
+
data.tar.gz: 64a1063477787141603fd850b6de704223c15b8dd6dbedcd713ea4a5ae69fb1ebf630ba1eaef9fc245a95272f4b32b40618065e04e0c69d72b8536677ef107bd
|
data/README.md
CHANGED
@@ -8,7 +8,10 @@
|
|
8
8
|

|
9
9
|
[](https://github.com/Mati365/ckeditor5-rails/issues)
|
10
10
|
|
11
|
-
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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 :
|
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(
|
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
|
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
|
@@ -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|
|
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|
|
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
|
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
|
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|
|
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
|
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.
|
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-
|
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
|