ckeditor5 1.25.0 → 1.26.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: 51c0f877edf5aa0ddc0c6b2333f5b631f1ce04144a84eb20c4555bfe63d3206b
4
- data.tar.gz: 5d477a6bdf0d8fd05fc3bfedfe34f33398a1c58a015a5de8f6871afd1f38f4bb
3
+ metadata.gz: b30c6cdd98e034209f4dd07ffa70d5a209c207fc1f7a7b37dfd58192a12ac4bc
4
+ data.tar.gz: e36f7f055fc52af917e2b146653879172a840af29e16665a650c6331092a18a7
5
5
  SHA512:
6
- metadata.gz: 401eb14e4e732e5ac3bd1d249372234b0d134277ad934e1cf38968a121824004266acf00ec71699ef3325288a28346fa42254735480207bc3d3a1c901b4b49d9
7
- data.tar.gz: 21679ec808b05ff0c052fe419799e47a44b6587b66119cc43d2092c969f0634f52ee8f34c2a8a93eb5300e50c2c7e258cb3d8a4d073898b86ca07d4f1070839b
6
+ metadata.gz: de3f06d82c4dedc97d34e3082a2f1aaf13323b9fb15ed0bc68d126fa4f63890234206e5fc52528e27332937d9330fc70440b687cc91a7facfe6f8a7b04271836
7
+ data.tar.gz: 26c4eeb0617420bd283841c0bd4bd77a3516eef5287e59a7388591bc6f8538838c7abba67ccc20fc4a32db5662daa8c168954767eb158a96a4cfcc626ed36310
data/README.md CHANGED
@@ -119,8 +119,7 @@ For extending CKEditor's functionality, refer to the [plugins directory](https:/
119
119
  - [Automatic upgrades 🔄](#automatic-upgrades-)
120
120
  - [Available Configuration Methods ⚙️](#available-configuration-methods-️)
121
121
  - [`cdn(cdn = nil, &block)` method](#cdncdn--nil-block-method)
122
- - [`version(version)` method](#versionversion-method)
123
- - [`automatic_upgrades(enabled: true)` method](#automatic_upgradesenabled-true-method)
122
+ - [`version(version, apply_patches: true)` method](#versionversion-apply_patches-true-method)
124
123
  - [`gpl` method](#gpl-method)
125
124
  - [`license_key(key)` method](#license_keykey-method)
126
125
  - [`premium` method](#premium-method)
@@ -138,6 +137,8 @@ For extending CKEditor's functionality, refer to the [plugins directory](https:/
138
137
  - [`plugins(*names, **kwargs)` method](#pluginsnames-kwargs-method)
139
138
  - [`inline_plugin(name, code)` method](#inline_pluginname-code-method)
140
139
  - [`external_plugin(name, script:, import_as: nil, window_name: nil, stylesheets: [])` method](#external_pluginname-script-import_as-nil-window_name-nil-stylesheets--method)
140
+ - [`patch_plugin(plugin)`](#patch_pluginplugin)
141
+ - [`apply_integration_patches` method](#apply_integration_patches-method)
141
142
  - [`simple_upload_adapter(url)` method](#simple_upload_adapterurl-method)
142
143
  - [`special_characters(&block)` method](#special_charactersblock-method)
143
144
  - [`wproofreader(version: nil, cdn: nil, **config)` method](#wproofreaderversion-nil-cdn-nil-config-method)
@@ -317,7 +318,7 @@ end
317
318
  ```
318
319
  </details>
319
320
 
320
- #### `version(version)` method
321
+ #### `version(version, apply_patches: true)` method
321
322
 
322
323
  <details>
323
324
  <summary>Set up the version of CKEditor 5 to be used by the integration</summary>
@@ -335,6 +336,23 @@ CKEditor5::Rails.configure do
335
336
  version '44.1.0'
336
337
  end
337
338
  ```
339
+
340
+ In order to disable default patches, you can pass the `apply_patches: false` keyword argument to the `version` method.
341
+
342
+ ```rb
343
+ # config/initializers/ckeditor5.rb
344
+
345
+ CKEditor5::Rails.configure do
346
+ # ... other configuration
347
+
348
+ version '44.1.0', apply_patches: false
349
+ end
350
+ ```
351
+
352
+ The patches are defined in the `lib/ckeditor5/rails/plugins/patches` directory. If you want to apply custom patches, you can use the `patch_plugin` method.
353
+
354
+ ```rb
355
+
338
356
  </details>
339
357
 
340
358
  #### `automatic_upgrades(enabled: true)` method
@@ -979,6 +997,76 @@ end
979
997
 
980
998
  </details>
981
999
 
1000
+ #### `patch_plugin(plugin)`
1001
+
1002
+ <details>
1003
+ <summary>Appends plugin that applies patch to the specific versions of CKEditor 5</summary>
1004
+
1005
+ <br />
1006
+
1007
+ Defines a plugin that applies a patch to the specific versions of CKEditor 5. The example below shows how to define a plugin that applies a patch to the `44.1.0` version:
1008
+
1009
+ ```rb
1010
+ # config/initializers/ckeditor5.rb
1011
+
1012
+ CKEditor5::Rails.configure do
1013
+ # ... other configuration
1014
+
1015
+ patch_plugin MyPatchPlugin.new
1016
+ end
1017
+ ```
1018
+
1019
+ where the `MyPatchPlugin` should inherit from `KEditor5::Rails::Editor::PropsPatchPlugin` and implement the `initialize` method. For example:
1020
+
1021
+ ```rb
1022
+ class YourPatch < CKEditor5::Rails::Editor::PropsPatchPlugin
1023
+ PLUGIN_CODE = <<~JS
1024
+ const { Plugin, ColorPickerView, debounce } = await import( 'ckeditor5' );
1025
+
1026
+ return class YourPatch extends Plugin {
1027
+ static get pluginName() {
1028
+ return 'YourPatch';
1029
+ }
1030
+
1031
+ constructor(editor) {
1032
+ super(editor);
1033
+
1034
+ // ... your patch
1035
+ }
1036
+ }
1037
+ JS
1038
+
1039
+ def initialize
1040
+ super(:YourPatch, PLUGIN_CODE, min_version: nil, max_version: '45.0.0')
1041
+ compress!
1042
+ end
1043
+ end
1044
+ ```
1045
+ </details>
1046
+
1047
+ #### `apply_integration_patches` method
1048
+
1049
+ <details>
1050
+ <summary>Apply patches to the specific versions of CKEditor 5</summary>
1051
+
1052
+ <br />
1053
+
1054
+ Defines a method that applies patches to the specific versions of CKEditor 5. The example below shows how to apply patches to the `44.1.0` version:
1055
+
1056
+ ```rb
1057
+ # config/initializers/ckeditor5.rb
1058
+
1059
+ CKEditor5::Rails.configure do
1060
+ # ... other configuration
1061
+
1062
+ apply_integration_patches
1063
+ end
1064
+ ```
1065
+
1066
+ It's useful when you want to apply patches to the specific versions of CKEditor 5. The patches are defined in the `lib/ckeditor5/rails/plugins/patches` directory.
1067
+
1068
+ </details>
1069
+
982
1070
  #### `simple_upload_adapter(url)` method
983
1071
 
984
1072
  <details>
@@ -73,7 +73,7 @@ module CKEditor5::Rails
73
73
  type ||= preset.type
74
74
 
75
75
  # Add some fallbacks
76
- config[:licenseKey] ||= context[:license_key]
76
+ config[:licenseKey] ||= context[:license_key] || preset.license_key
77
77
  config[:language] = { ui: language } if language
78
78
 
79
79
  editor_props = Editor::Props.new(
@@ -3,6 +3,7 @@
3
3
  require_relative 'props_plugin'
4
4
  require_relative 'props_inline_plugin'
5
5
  require_relative 'props_external_plugin'
6
+ require_relative 'props_patch_plugin'
6
7
  require_relative 'props'
7
8
 
8
9
  module CKEditor5::Rails::Editor::Helpers
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../semver'
4
+ require_relative 'props_inline_plugin'
5
+
6
+ module CKEditor5::Rails::Editor
7
+ class PropsPatchPlugin < PropsInlinePlugin
8
+ attr_reader :min_version, :max_version
9
+
10
+ def initialize(name, code, min_version: nil, max_version: nil)
11
+ super(name, code)
12
+
13
+ @min_version = min_version && CKEditor5::Rails::Semver.new(min_version)
14
+ @max_version = max_version && CKEditor5::Rails::Semver.new(max_version)
15
+
16
+ compress!
17
+ end
18
+
19
+ def self.applicable_for_version?(editor_version, min_version: nil, max_version: nil)
20
+ return true if min_version.nil? && max_version.nil?
21
+
22
+ current_version = CKEditor5::Rails::Semver.new(editor_version)
23
+
24
+ min_check = min_version.nil? || current_version >= CKEditor5::Rails::Semver.new(min_version)
25
+ max_check = max_version.nil? || current_version <= CKEditor5::Rails::Semver.new(max_version)
26
+
27
+ min_check && max_check
28
+ end
29
+
30
+ def applicable_for_version?(editor_version)
31
+ self.class.applicable_for_version?(
32
+ editor_version,
33
+ min_version: @min_version&.to_s,
34
+ max_version: @max_version&.to_s
35
+ )
36
+ end
37
+ end
38
+ end
@@ -3,9 +3,7 @@
3
3
  require 'rails/engine'
4
4
 
5
5
  require_relative 'presets/manager'
6
- require_relative 'plugins/simple_upload_adapter'
7
- require_relative 'plugins/wproofreader'
8
- require_relative 'plugins/special_characters_bootstrap'
6
+ require_relative 'plugins'
9
7
 
10
8
  module CKEditor5::Rails
11
9
  class PresetNotFoundError < ArgumentError; end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../editor/props_patch_plugin'
4
+
5
+ module CKEditor5::Rails::Plugins::Patches
6
+ # Fixes focus management issues in the CKEditor5 color picker component
7
+ # by ensuring proper focus handling when the color picker is opened.
8
+ #
9
+ # The patch modifies the ColorPickerView's focus behavior to properly
10
+ # focus either the hex input field (when visible) or the first slider.
11
+ #
12
+ # @see https://github.com/ckeditor/ckeditor5/issues/17069
13
+ class FixColorPickerRaceCondition < CKEditor5::Rails::Editor::PropsPatchPlugin
14
+ PLUGIN_CODE = <<~JS
15
+ const { Plugin, ColorPickerView, debounce } = await import( 'ckeditor5' );
16
+
17
+ return class FixColorPickerRaceCondition extends Plugin {
18
+ static get pluginName() {
19
+ return 'FixColorPickerRaceCondition';
20
+ }
21
+
22
+ constructor(editor) {
23
+ super(editor);
24
+ this.editor = editor;
25
+ this.#applyPatch();
26
+ }
27
+
28
+ #applyPatch() {
29
+ const { focus } = ColorPickerView.prototype;
30
+
31
+ ColorPickerView.prototype.focus = function() {
32
+ try {
33
+ if (!this._config.hideInput) {
34
+ this.hexInputRow.children.get( 1 ).focus();
35
+ }
36
+
37
+ this.slidersView.first.focus();
38
+ } catch (error) {
39
+ focus.apply(this, arguments);
40
+ }
41
+ }
42
+ }
43
+ }
44
+ JS
45
+
46
+ def initialize
47
+ super(:FixColorPickerRaceCondition, PLUGIN_CODE, max_version: '44.4.0')
48
+ compress!
49
+ end
50
+ end
51
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../editor/props_external_plugin'
4
3
  require_relative '../editor/props_inline_plugin'
5
4
 
6
5
  module CKEditor5::Rails::Plugins
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5::Rails::Plugins
4
+ module Patches
5
+ end
6
+ end
7
+
8
+ # Core plugins
9
+ require_relative 'plugins/simple_upload_adapter'
10
+ require_relative 'plugins/wproofreader'
11
+ require_relative 'plugins/special_characters_bootstrap'
12
+
13
+ # Plugin patches and fixes
14
+ require_relative 'plugins/patches/fix_color_picker_race_condition'
@@ -12,6 +12,7 @@ module CKEditor5::Rails
12
12
  class DisallowedInlinePluginError < ArgumentError; end
13
13
  class MissingInlinePluginError < StandardError; end
14
14
  class UnsupportedESModuleError < StandardError; end
15
+ class InvalidPatchPluginError < ArgumentError; end
15
16
 
16
17
  included do
17
18
  attr_reader :disallow_inline_plugins, :disallow_inline_plugin_compression
@@ -67,6 +68,23 @@ module CKEditor5::Rails
67
68
  register_plugin(plugin)
68
69
  end
69
70
 
71
+ # Registers a patch plugin that modifies CKEditor behavior for specific versions
72
+ #
73
+ # @param plugin [Editor::PropsPatchPlugin] Patch plugin instance to register
74
+ # @raise [InvalidPatchPluginError] When provided plugin is not a PropsPatchPlugin
75
+ # @return [Editor::PropsPatchPlugin, nil] Returns plugin if registered, nil if not applicable
76
+ # @example Apply patch for specific CKEditor versions
77
+ # patch_plugin PropsPatchPlugin.new(:PatchName, code, min_version: '35.0.0', max_version: '36.0.0')
78
+ def patch_plugin(plugin)
79
+ unless plugin.is_a?(Editor::PropsPatchPlugin)
80
+ raise InvalidPatchPluginError, 'Provided plugin must be a PropsPatchPlugin instance'
81
+ end
82
+
83
+ return unless !@version || plugin.applicable_for_version?(@version)
84
+
85
+ register_plugin(plugin)
86
+ end
87
+
70
88
  # Register a single plugin by name
71
89
  #
72
90
  # @param name [Symbol, Editor::PropsBasePlugin] Plugin name or instance
@@ -109,8 +127,10 @@ module CKEditor5::Rails
109
127
  # Check if the plugin looks like an inline plugin
110
128
  # @param plugin [Editor::PropsBasePlugin] Plugin instance
111
129
  # @return [Boolean] True if the plugin is an inline plugin
112
- def looks_like_inline_plugin?(plugin)
113
- plugin.respond_to?(:code) && plugin.code.present?
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)
114
134
  end
115
135
 
116
136
  # Register a plugin in the editor configuration.
@@ -122,7 +142,7 @@ module CKEditor5::Rails
122
142
  # @param plugin_obj [Editor::PropsBasePlugin] Plugin instance to register
123
143
  # @return [Editor::PropsBasePlugin] The registered plugin
124
144
  def register_plugin(plugin_obj)
125
- if disallow_inline_plugins && looks_like_inline_plugin?(plugin_obj)
145
+ if disallow_inline_plugins && looks_like_unsafe_inline_plugin?(plugin_obj)
126
146
  raise DisallowedInlinePluginError, 'Inline plugins are not allowed here.'
127
147
  end
128
148
 
@@ -172,11 +172,16 @@ module CKEditor5::Rails
172
172
  end
173
173
 
174
174
  # Set or get editor version
175
- # @param version [String, nil] Editor version
175
+ # @param version [String, nil] Editor version to set
176
+ # @param apply_patches [Boolean] Whether to apply integration patches after setting version
176
177
  # @example Set specific version
177
178
  # version '43.3.1'
178
- # @return [String, nil] Current version
179
- def version(version = nil)
179
+ # @example Set version without applying patches
180
+ # version '43.3.1', apply_patches: false
181
+ # @example Get current version
182
+ # version # => "43.3.1"
183
+ # @return [String, nil] Current version string or nil if not set
184
+ def version(version = nil, apply_patches: true)
180
185
  return @version&.to_s if version.nil?
181
186
 
182
187
  if @automatic_upgrades && version
@@ -185,6 +190,17 @@ module CKEditor5::Rails
185
190
  else
186
191
  @version = Semver.new(version)
187
192
  end
193
+
194
+ # If there is no license key set, and the version if newer than 44.0.0, switch to GPL
195
+ # as the license key is now required in all versions
196
+ gpl if license_key.nil? && @version.major >= 44
197
+ apply_integration_patches if apply_patches
198
+ end
199
+
200
+ # Apply integration patches for the current version
201
+ # @return [void]
202
+ def apply_integration_patches
203
+ patch_plugin Plugins::Patches::FixColorPickerRaceCondition.new
188
204
  end
189
205
 
190
206
  # Enable or disable automatic version upgrades
@@ -10,6 +10,13 @@ module CKEditor5
10
10
  include Comparable
11
11
 
12
12
  def initialize(version_string)
13
+ if version_string.is_a?(Semver)
14
+ @major = version_string.major
15
+ @minor = version_string.minor
16
+ @patch = version_string.patch
17
+ return
18
+ end
19
+
13
20
  validate!(version_string)
14
21
  @major, @minor, @patch = version_string.split('.').map(&:to_i)
15
22
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CKEditor5
4
4
  module Rails
5
- VERSION = '1.25.0'
5
+ VERSION = '1.26.1'
6
6
 
7
7
  DEFAULT_CKEDITOR_VERSION = '44.1.0'
8
8
  end
@@ -20,7 +20,7 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
20
20
  let(:helper) { test_class.new }
21
21
  let(:preset) do
22
22
  CKEditor5::Rails::Presets::PresetBuilder.new do
23
- version '34.1.0'
23
+ version '34.1.0', apply_patches: false
24
24
  type :classic
25
25
  translations :pl
26
26
  cdn :cloud
@@ -151,7 +151,7 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
151
151
  context 'when overriding preset values' do
152
152
  let(:preset) do
153
153
  CKEditor5::Rails::Presets::PresetBuilder.new do
154
- version '34.1.0'
154
+ version '34.1.0', apply_patches: false
155
155
  type :classic
156
156
  language :pl
157
157
  cdn :cloud
@@ -24,6 +24,7 @@ RSpec.describe CKEditor5::Rails::Editor::Helpers::Editor do
24
24
  allow(preset).to receive(:config).and_return({})
25
25
  allow(preset).to receive(:automatic_upgrades?).and_return(false)
26
26
  allow(preset).to receive(:editable_height).and_return(nil)
27
+ allow(preset).to receive(:license_key).and_return(nil)
27
28
  end
28
29
 
29
30
  before do
@@ -225,6 +226,18 @@ RSpec.describe CKEditor5::Rails::Editor::Helpers::Editor do
225
226
  expect(helper.ckeditor5_editor(editable_height: 600)).to include('editable-height="600px"')
226
227
  end
227
228
  end
229
+
230
+ context 'when using license key' do
231
+ it 'uses license key from preset when no other license key is provided' do
232
+ custom_context = { preset: :default, bundle: 'custom-bundle' }
233
+ allow(helper).to receive(:ckeditor5_context_or_fallback).and_return(custom_context)
234
+
235
+ allow(preset).to receive(:license_key).and_return('preset-license-key')
236
+
237
+ result = helper.ckeditor5_editor
238
+ expect(result).to include('preset-license-key')
239
+ end
240
+ end
228
241
  end
229
242
 
230
243
  describe '#ckeditor5_editable' do
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Editor::PropsPatchPlugin do
6
+ let(:plugin_name) { 'testPlugin' }
7
+ let(:plugin_code) { 'console.log("test");' }
8
+
9
+ describe '#initialize' do
10
+ it 'creates plugin with version constraints' do
11
+ plugin = described_class.new(plugin_name, plugin_code, min_version: '29.0.0', max_version: '30.0.0')
12
+
13
+ expect(plugin.min_version.to_s).to eq('29.0.0')
14
+ expect(plugin.max_version.to_s).to eq('30.0.0')
15
+ end
16
+
17
+ it 'creates plugin without version constraints' do
18
+ plugin = described_class.new(plugin_name, plugin_code)
19
+
20
+ expect(plugin.min_version).to be_nil
21
+ expect(plugin.max_version).to be_nil
22
+ end
23
+ end
24
+
25
+ describe '.applicable_for_version?' do
26
+ it 'returns true when no version constraints' do
27
+ expect(described_class.applicable_for_version?('29.0.0')).to be true
28
+ end
29
+
30
+ it 'returns true when version is within constraints' do
31
+ result = described_class.applicable_for_version?(
32
+ '29.1.0',
33
+ min_version: '29.0.0',
34
+ max_version: '30.0.0'
35
+ )
36
+ expect(result).to be true
37
+ end
38
+
39
+ it 'returns true when version is equal to min constraint' do
40
+ result = described_class.applicable_for_version?(
41
+ '29.0.0',
42
+ min_version: '29.0.0'
43
+ )
44
+ expect(result).to be true
45
+ end
46
+
47
+ it 'returns true when version is equal to max constraint' do
48
+ result = described_class.applicable_for_version?(
49
+ '30.0.0',
50
+ max_version: '30.0.0'
51
+ )
52
+ expect(result).to be true
53
+ end
54
+
55
+ it 'returns true when version is higher than min constraint (patch)' do
56
+ result = described_class.applicable_for_version?(
57
+ '29.0.1',
58
+ min_version: '29.0.0'
59
+ )
60
+ expect(result).to be true
61
+ end
62
+
63
+ it 'returns true when version is higher than min constraint (minor)' do
64
+ result = described_class.applicable_for_version?(
65
+ '29.1.0',
66
+ min_version: '29.0.0'
67
+ )
68
+ expect(result).to be true
69
+ end
70
+
71
+ it 'returns true when version is higher than min constraint (major)' do
72
+ result = described_class.applicable_for_version?(
73
+ '30.0.0',
74
+ min_version: '29.0.0'
75
+ )
76
+ expect(result).to be true
77
+ end
78
+
79
+ it 'returns false when version is not equal to max constraint (patch)' do
80
+ result = described_class.applicable_for_version?(
81
+ '30.0.1',
82
+ max_version: '30.0.0'
83
+ )
84
+ expect(result).to be false
85
+ end
86
+
87
+ it 'returns false when version is not equal to min constraint (minor)' do
88
+ result = described_class.applicable_for_version?(
89
+ '29.1.0',
90
+ max_version: '29.0.0'
91
+ )
92
+ expect(result).to be false
93
+ end
94
+
95
+ it 'returns false when version is too low' do
96
+ result = described_class.applicable_for_version?(
97
+ '28.9.9',
98
+ min_version: '29.0.0',
99
+ max_version: '30.0.0'
100
+ )
101
+ expect(result).to be false
102
+ end
103
+
104
+ it 'returns false when version is too high' do
105
+ result = described_class.applicable_for_version?(
106
+ '30.0.1',
107
+ min_version: '29.0.0',
108
+ max_version: '30.0.0'
109
+ )
110
+ expect(result).to be false
111
+ end
112
+ end
113
+
114
+ describe '#applicable_for_version?' do
115
+ context 'with both version constraints' do
116
+ let(:plugin) do
117
+ described_class.new(plugin_name, plugin_code, min_version: '29.0.0', max_version: '30.0.0')
118
+ end
119
+
120
+ it 'returns true for version within constraints' do
121
+ expect(plugin.applicable_for_version?('29.1.0')).to be true
122
+ end
123
+
124
+ it 'returns false for version outside constraints' do
125
+ expect(plugin.applicable_for_version?('28.9.9')).to be false
126
+ end
127
+ end
128
+
129
+ context 'with only min_version constraint' do
130
+ let(:plugin) do
131
+ described_class.new(plugin_name, plugin_code, min_version: '29.0.0')
132
+ end
133
+
134
+ it 'returns true for version above min_version' do
135
+ expect(plugin.applicable_for_version?('30.0.0')).to be true
136
+ end
137
+
138
+ it 'returns false for version below min_version' do
139
+ expect(plugin.applicable_for_version?('28.9.9')).to be false
140
+ end
141
+ end
142
+
143
+ context 'with only max_version constraint' do
144
+ let(:plugin) do
145
+ described_class.new(plugin_name, plugin_code, max_version: '30.0.0')
146
+ end
147
+
148
+ it 'returns true for version below max_version' do
149
+ expect(plugin.applicable_for_version?('29.0.0')).to be true
150
+ end
151
+
152
+ it 'returns false for version above max_version' do
153
+ expect(plugin.applicable_for_version?('30.0.1')).to be false
154
+ end
155
+ end
156
+ end
157
+ end
@@ -20,7 +20,7 @@ RSpec.describe CKEditor5::Rails::Presets::Manager do
20
20
  it 'creates new preset based on default' do
21
21
  manager.define(:custom) do
22
22
  automatic_upgrades enabled: false
23
- version '36.0.0'
23
+ version '36.0.0', apply_patches: false
24
24
  end
25
25
 
26
26
  expect(manager[:custom].version).to eq('36.0.0')
@@ -32,7 +32,7 @@ RSpec.describe CKEditor5::Rails::Presets::Manager do
32
32
  it 'creates completely new preset' do
33
33
  manager.define(:custom, inherit: false) do
34
34
  automatic_upgrades enabled: false
35
- version '36.0.0'
35
+ version '36.0.0', apply_patches: false
36
36
  end
37
37
 
38
38
  expect(manager[:custom].version).to eq('36.0.0')
@@ -31,6 +31,34 @@ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
31
31
  end
32
32
  end
33
33
 
34
+ describe '#version' do
35
+ it 'sets version' do
36
+ builder.version '35.0.0'
37
+ expect(builder.version).to eq('35.0.0')
38
+ end
39
+
40
+ context 'with version >= 44.0.0' do
41
+ it 'sets GPL license when no license key is set' do
42
+ builder.version('44.0.0')
43
+ expect(builder.license_key).to eq('GPL')
44
+ expect(builder.premium?).to be false
45
+ end
46
+
47
+ it 'does not change license when license key is already set' do
48
+ builder.license_key('commercial-key')
49
+ builder.version('44.0.0')
50
+ expect(builder.license_key).to eq('commercial-key')
51
+ end
52
+ end
53
+
54
+ context 'with version < 44.0.0' do
55
+ it 'does not set GPL license automatically' do
56
+ builder.version('43.0.0')
57
+ expect(builder.license_key).to be_nil
58
+ end
59
+ end
60
+ end
61
+
34
62
  describe '#initialize_copy' do
35
63
  let(:original) do
36
64
  described_class.new do
@@ -520,6 +548,10 @@ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
520
548
  end
521
549
 
522
550
  describe '#special_characters' do
551
+ it 'should not crash if block is not provided' do
552
+ expect { builder.special_characters }.not_to raise_error
553
+ end
554
+
523
555
  it 'configures special characters with groups and items' do # rubocop:disable Metrics/BlockLength
524
556
  builder.special_characters do
525
557
  group 'Emoji', label: 'Emoticons' do
@@ -542,36 +574,38 @@ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
542
574
  order :Text, :Arrows, :Emoji, :Mixed
543
575
  end
544
576
 
545
- expect(builder.config[:specialCharactersBootstrap]).to eq({
546
- groups: [
547
- {
548
- name: 'Emoji',
549
- items: [
550
- { title: 'smiley', character: '😊' },
551
- { title: 'heart', character: '❤️' }
552
- ],
553
- options: { label: 'Emoticons' }
554
- },
555
- {
556
- name: 'Arrows',
557
- items: [
558
- { title: 'right', character: '→' },
559
- { title: 'left', character: '←' }
560
- ],
561
- options: {}
562
- },
563
- {
564
- name: 'Mixed',
565
- items: [
566
- { title: 'star', character: '⭐' },
567
- { title: 'heart', character: '❤️' }
568
- ],
569
- options: { label: 'Mixed Characters' }
570
- }
571
- ],
572
- order: %w[Text Arrows Emoji Mixed],
573
- packs: []
574
- })
577
+ data = {
578
+ groups: [
579
+ {
580
+ name: 'Emoji',
581
+ items: [
582
+ { title: 'smiley', character: '😊' },
583
+ { title: 'heart', character: '❤️' }
584
+ ],
585
+ options: { label: 'Emoticons' }
586
+ },
587
+ {
588
+ name: 'Arrows',
589
+ items: [
590
+ { title: 'right', character: '→' },
591
+ { title: 'left', character: '←' }
592
+ ],
593
+ options: {}
594
+ },
595
+ {
596
+ name: 'Mixed',
597
+ items: [
598
+ { title: 'star', character: '⭐' },
599
+ { title: 'heart', character: '❤️' }
600
+ ],
601
+ options: { label: 'Mixed Characters' }
602
+ }
603
+ ],
604
+ order: %w[Text Arrows Emoji Mixed],
605
+ packs: []
606
+ }
607
+
608
+ expect(builder.config[:specialCharactersBootstrap]).to eq(data)
575
609
 
576
610
  plugin_names = builder.config[:plugins].map(&:name)
577
611
  expect(plugin_names).to include(:SpecialCharacters)
@@ -593,4 +627,70 @@ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
593
627
  )
594
628
  end
595
629
  end
630
+
631
+ describe '#patch_plugin' do
632
+ let(:patch_plugin) do
633
+ CKEditor5::Rails::Editor::PropsPatchPlugin.new(
634
+ :TestPatch,
635
+ <<~JAVASCRIPT
636
+ const { Plugin } = await import('ckeditor5');
637
+ return class TestPatch extends Plugin {
638
+ init() {}
639
+ }
640
+ JAVASCRIPT
641
+ )
642
+ end
643
+
644
+ it 'raises error when plugin is not a PropsPatchPlugin' do
645
+ invalid_plugin = CKEditor5::Rails::Editor::PropsPlugin.new(:InvalidPatch)
646
+
647
+ expect { builder.patch_plugin(invalid_plugin) }
648
+ .to raise_error(
649
+ CKEditor5::Rails::Presets::Concerns::PluginMethods::InvalidPatchPluginError,
650
+ 'Provided plugin must be a PropsPatchPlugin instance'
651
+ )
652
+ end
653
+
654
+ it 'applies patch when applicable' do
655
+ allow(patch_plugin).to receive(:applicable_for_version?).and_return(true)
656
+
657
+ builder.version('35.0.0', apply_patches: false)
658
+ builder.patch_plugin(patch_plugin)
659
+
660
+ plugin_names = builder.config[:plugins].map(&:name)
661
+ expect(plugin_names).to include(:TestPatch)
662
+ end
663
+
664
+ it 'skips patch when not applicable' do
665
+ allow(patch_plugin).to receive(:applicable_for_version?).and_return(false)
666
+
667
+ builder.version('35.0.0')
668
+ builder.patch_plugin(patch_plugin)
669
+
670
+ plugin_names = builder.config[:plugins].map(&:name)
671
+ expect(plugin_names).not_to include(:TestPatch)
672
+ end
673
+
674
+ it 'applies patch when version is not set' do
675
+ builder.patch_plugin(patch_plugin)
676
+
677
+ plugin_names = builder.config[:plugins].map(&:name)
678
+ expect(plugin_names).to include(:TestPatch)
679
+ end
680
+ end
681
+
682
+ describe '#apply_integration_patches' do
683
+ it 'applies known integration patches' do
684
+ builder.version('35.0.0', apply_patches: false)
685
+ expect { builder.apply_integration_patches }
686
+ .to change { builder.config[:plugins].count }
687
+ .by(1)
688
+ end
689
+
690
+ it 'apply patches when version is not set' do
691
+ expect { builder.apply_integration_patches }
692
+ .to change { builder.config[:plugins].count }
693
+ .by(1)
694
+ end
695
+ end
596
696
  end
@@ -8,6 +8,15 @@ RSpec.describe CKEditor5::Rails::Semver do
8
8
  it 'accepts version in x.y.z format' do
9
9
  expect { described_class.new('1.2.3') }.not_to raise_error
10
10
  end
11
+
12
+ it 'accepts Semver object' do
13
+ original = described_class.new('1.2.3')
14
+ copied = described_class.new(original)
15
+
16
+ expect(copied.major).to eq(1)
17
+ expect(copied.minor).to eq(2)
18
+ expect(copied.patch).to eq(3)
19
+ end
11
20
  end
12
21
 
13
22
  context 'with invalid version' do
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.25.0
4
+ version: 1.26.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-05 00:00:00.000000000 Z
12
+ date: 2025-02-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -82,12 +82,15 @@ files:
82
82
  - lib/ckeditor5/rails/editor/props_base_plugin.rb
83
83
  - lib/ckeditor5/rails/editor/props_external_plugin.rb
84
84
  - lib/ckeditor5/rails/editor/props_inline_plugin.rb
85
+ - lib/ckeditor5/rails/editor/props_patch_plugin.rb
85
86
  - lib/ckeditor5/rails/editor/props_plugin.rb
86
87
  - lib/ckeditor5/rails/engine.rb
87
88
  - lib/ckeditor5/rails/helpers.rb
88
89
  - lib/ckeditor5/rails/hooks/form.rb
89
90
  - lib/ckeditor5/rails/hooks/importmap.rb
90
91
  - lib/ckeditor5/rails/hooks/simple_form.rb
92
+ - lib/ckeditor5/rails/plugins.rb
93
+ - lib/ckeditor5/rails/plugins/patches/fix_color_picker_race_condition.rb
91
94
  - lib/ckeditor5/rails/plugins/simple_upload_adapter.rb
92
95
  - lib/ckeditor5/rails/plugins/special_characters_bootstrap.rb
93
96
  - lib/ckeditor5/rails/plugins/wproofreader.rb
@@ -125,6 +128,7 @@ files:
125
128
  - spec/lib/ckeditor5/rails/editor/props_base_plugin_spec.rb
126
129
  - spec/lib/ckeditor5/rails/editor/props_external_plugin_spec.rb
127
130
  - spec/lib/ckeditor5/rails/editor/props_inline_plugin_spec.rb
131
+ - spec/lib/ckeditor5/rails/editor/props_patch_plugin_spec.rb
128
132
  - spec/lib/ckeditor5/rails/editor/props_plugin_spec.rb
129
133
  - spec/lib/ckeditor5/rails/editor/props_spec.rb
130
134
  - spec/lib/ckeditor5/rails/engine_spec.rb
@@ -194,6 +198,7 @@ test_files:
194
198
  - spec/lib/ckeditor5/rails/editor/props_base_plugin_spec.rb
195
199
  - spec/lib/ckeditor5/rails/editor/props_external_plugin_spec.rb
196
200
  - spec/lib/ckeditor5/rails/editor/props_inline_plugin_spec.rb
201
+ - spec/lib/ckeditor5/rails/editor/props_patch_plugin_spec.rb
197
202
  - spec/lib/ckeditor5/rails/editor/props_plugin_spec.rb
198
203
  - spec/lib/ckeditor5/rails/editor/props_spec.rb
199
204
  - spec/lib/ckeditor5/rails/engine_spec.rb