ckeditor5 1.17.3 → 1.18.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe514f6683b41d1fff1a64788a8ab4a608a567563fb904c7af684c9d24f94fe9
4
- data.tar.gz: 411ce73542f83467ae713fbf8bd2976a3597b82f2df4b7cc8ee19ab93cc65ea2
3
+ metadata.gz: e22407a5c1e37a744b94252008f0cba4be068964b5503661ef5441fb090831c7
4
+ data.tar.gz: eeb8757cf2c15de70ed40b9652071bfb1aa7bb9224a14842238d2d0670fa3f9e
5
5
  SHA512:
6
- metadata.gz: b3420f1f381e795d37416b0038dba3c60980a2038d959a267ab6c70cbaf883af7e12ee3bcdd9a3f80c2ff27edb38d01c2da1a98133aa08cd6736e01e8d6d25db
7
- data.tar.gz: 2a1102d9f90cf10f41a28b8d644d1d51c88a1b90553d3b65c8c8d486180282a9bcb61a3d5f5975333616711da7e3129632f0cb50bc835c43e131102beed62918
6
+ metadata.gz: 06a0b97e9bd86bbba3c905b283f9fdebcf83dd5014bec69caca4898141f937db802b5036d5671dc2e72aa7c7f31b4174876e9ac9499696cf61a85e05d8c65e94
7
+ data.tar.gz: '09c16514d790101da1069e1de3db5a1ba59b28e70d322f41958cd62be12fc5ceb2fea06a7d474d566845186b468161cca1d596f2c764780baa09f1174ff49305'
data/Gemfile CHANGED
@@ -8,7 +8,6 @@ group :development do
8
8
  gem 'brakeman', '~> 6.1', '>= 6.1.1', require: false
9
9
  gem 'guard', '~> 2.19', '>= 2.19.0'
10
10
  gem 'guard-process', '~> 1.2'
11
- gem 'guard-rspec', '~> 4.7', '>= 4.7.3'
12
11
  gem 'pry', '~> 0.15', '>= 0.15.0'
13
12
  gem 'pry-rails', '~> 0.3', '>= 0.3.11'
14
13
  gem 'rails', '~> 7.0', '>= 7.0.0'
data/README.md CHANGED
@@ -129,7 +129,9 @@ For extending CKEditor's functionality, refer to the [plugins directory](https:/
129
129
  - [`plugin(name, premium:, import_name:)` method](#pluginname-premium-import_name-method)
130
130
  - [`plugins(*names, **kwargs)` method](#pluginsnames-kwargs-method)
131
131
  - [`inline_plugin(name, code)` method](#inline_pluginname-code-method)
132
+ - [`external_plugin(name, script:, import_as: nil, window_name: nil, stylesheets: [])` method](#external_pluginname-script-import_as-nil-window_name-nil-stylesheets--method)
132
133
  - [`simple_upload_adapter(url)` method](#simple_upload_adapterurl-method)
134
+ - [`wproofreader(version: nil, cdn: nil, **config)` method](#wproofreaderversion-nil-cdn-nil-config-method)
133
135
  - [Controller / View helpers 📦](#controller--view-helpers-)
134
136
  - [`ckeditor5_element_ref(selector)` method](#ckeditor5_element_refselector-method)
135
137
  - [`ckeditor5_preset(name = nil, &block)` method](#ckeditor5_presetname--nil-block-method)
@@ -790,6 +792,84 @@ end
790
792
  This approach is resistant to XSS attacks as it avoids inline JavaScript.
791
793
  </details>
792
794
 
795
+ #### `external_plugin(name, script:, import_as: nil, window_name: nil, stylesheets: [])` method
796
+
797
+ <details>
798
+ <summary>Define external CKEditor plugins directly in the configuration</summary>
799
+
800
+ <br />
801
+
802
+ Defines an external plugin to be included in the editor. You can pass the name of the plugin as an argument. The `script` keyword argument specifies the URL of the script to import the plugin from. The `import_as` keyword argument specifies the name of the package to import the plugin from. The `window_name` keyword argument specifies the name of the plugin in the window object. The `stylesheets` keyword argument specifies the URLs of the stylesheets to import.
803
+
804
+ The example below shows how to define an external plugin that highlights the text:
805
+
806
+ ```rb
807
+ # config/initializers/ckeditor5.rb
808
+
809
+ CKEditor5::Rails.configure do
810
+ # ... other configuration
811
+
812
+ external_plugin :MyExternalPlugin,
813
+ script: 'https://example.com/my-external-plugin.js'
814
+ end
815
+ ```
816
+
817
+ In order to import a plugin from a custom ESM package, you can pass the `import_as` keyword argument:
818
+
819
+ ```rb
820
+ # config/initializers/ckeditor5.rb
821
+
822
+ CKEditor5::Rails.configure do
823
+ # ... other configuration
824
+
825
+ external_plugin :MyExternalPlugin,
826
+ script: 'https://example.com/my-external-plugin.js',
827
+ import_as: 'Plugin'
828
+ end
829
+ ```
830
+
831
+ It's equivalent to the following JavaScript code:
832
+
833
+ ```js
834
+ import { Plugin } from 'my-external-plugin';
835
+ ```
836
+
837
+ In order to import a plugin from a custom Window entry, you can pass the `window_name` keyword argument:
838
+
839
+ ```rb
840
+ # config/initializers/ckeditor5.rb
841
+
842
+ CKEditor5::Rails.configure do
843
+ # ... other configuration
844
+
845
+ external_plugin :MyExternalPlugin,
846
+ script: 'https://example.com/my-external-plugin.js',
847
+ window_name: 'MyExternalPlugin'
848
+ end
849
+ ```
850
+
851
+ It's equivalent to the following JavaScript code:
852
+
853
+ ```js
854
+ const Plugin = window.MyExternalPlugin;
855
+ ```
856
+
857
+ In order to import a plugin with stylesheets, you can pass the `stylesheets` keyword argument:
858
+
859
+ ```rb
860
+ # config/initializers/ckeditor5.rb
861
+
862
+ CKEditor5::Rails.configure do
863
+ # ... other configuration
864
+
865
+ external_plugin :MyExternalPlugin,
866
+ script: 'https://example.com/my-external-plugin.js',
867
+ stylesheets: ['https://example.com/my-external-plugin.css']
868
+ end
869
+ ```
870
+
871
+ </details>
872
+
793
873
  #### `simple_upload_adapter(url)` method
794
874
 
795
875
  <details>
@@ -813,6 +893,43 @@ end
813
893
  ```
814
894
  </details>
815
895
 
896
+ #### `wproofreader(version: nil, cdn: nil, **config)` method
897
+
898
+ <details>
899
+ <summary>Configure WProofreader plugin</summary>
900
+
901
+ <br />
902
+
903
+ Defines the WProofreader plugin to be included in the editor. The example below shows how to include the WProofreader plugin:
904
+
905
+ ```rb
906
+ # config/initializers/ckeditor5.rb
907
+
908
+ CKEditor5::Rails.configure do
909
+ # ... other configuration
910
+
911
+ wproofreader serviceId: 'your-service-ID',
912
+ srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'
913
+ end
914
+ ```
915
+
916
+ The `version` keyword argument allows you to specify the version of the WProofreader plugin. The `cdn` keyword argument allows you to specify the CDN to be used for the WProofreader plugin.
917
+
918
+ ```rb
919
+ # config/initializers/ckeditor5.rb
920
+
921
+ CKEditor5::Rails.configure do
922
+ # ... other configuration
923
+
924
+ wproofreader version: '2.0.0',
925
+ cdn: :jsdelivr,
926
+ serviceId: 'your-service-ID',
927
+ srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'
928
+ end
929
+ ```
930
+
931
+ </details>
932
+
816
933
  ### Controller / View helpers 📦
817
934
 
818
935
  #### `ckeditor5_element_ref(selector)` method
@@ -41,7 +41,7 @@ module CKEditor5::Rails::Assets
41
41
  class JSUrlImportMeta
42
42
  attr_reader :url, :import_meta
43
43
 
44
- delegate :esm?, :window?, :import_name, :window_name, :import_as, :to_h, to: :import_meta
44
+ delegate :esm?, :window?, :import_name, :window_name, :import_as, to: :import_meta
45
45
 
46
46
  def initialize(url, translation: false, **import_options)
47
47
  @url = url
@@ -52,6 +52,10 @@ module CKEditor5::Rails::Assets
52
52
  def translation?
53
53
  @translation
54
54
  end
55
+
56
+ def to_h
57
+ import_meta.to_h.merge({ url: url })
58
+ end
55
59
  end
56
60
 
57
61
  class JSImportMeta
@@ -64,14 +68,14 @@ module CKEditor5::Rails::Assets
64
68
  @window_name = window_name
65
69
  end
66
70
 
67
- def esm?
68
- import_name.present?
69
- end
70
-
71
71
  def window?
72
72
  window_name.present?
73
73
  end
74
74
 
75
+ def esm?
76
+ import_name.present?
77
+ end
78
+
75
79
  def to_h
76
80
  {
77
81
  import_as: import_as,
@@ -44,7 +44,11 @@ function loadAsyncImports(imports = []) {
44
44
  return module.default;
45
45
  };
46
46
 
47
- const loadExternalPlugin = async ({ import_name, import_as, window_name }) => {
47
+ const loadExternalPlugin = async ({ import_name, import_as, window_name, stylesheets }) => {
48
+ if (stylesheets?.length) {
49
+ await loadAsyncCSS(stylesheets);
50
+ }
51
+
48
52
  if (window_name) {
49
53
  if (!Object.prototype.hasOwnProperty.call(window, window_name)) {
50
54
  throw new Error(
@@ -60,7 +64,11 @@ function loadAsyncImports(imports = []) {
60
64
  const imported = module[import_as || 'default'];
61
65
 
62
66
  if (!imported) {
63
- throw new Error(`Plugin "${import_as}" not found in the ESM module "${import_name}"!`);
67
+ throw new Error(
68
+ `Plugin "${import_as || 'default'}" not found in the ESM module ` +
69
+ `"${import_name}"! Available imports: ${Object.keys(module).join(', ')}! ` +
70
+ 'Consider changing "import_as" value.'
71
+ );
64
72
  }
65
73
 
66
74
  return imported;
@@ -78,6 +86,35 @@ function loadAsyncImports(imports = []) {
78
86
  }));
79
87
  }
80
88
 
89
+ /**
90
+ * Dynamically loads CSS files based on configuration
91
+ *
92
+ * @param {Array<string>} imports - Array of CSS file URLs to load
93
+ * @returns {Promise<Array<void>>} Array of promises for each CSS file load
94
+ * @throws {Error} When CSS file loading fails
95
+ */
96
+ function loadAsyncCSS(stylesheets = []) {
97
+ const promises = stylesheets.map(href =>
98
+ new Promise((resolve, reject) => {
99
+ const link = document.createElement('link');
100
+
101
+ link.rel = 'stylesheet';
102
+ link.href = href;
103
+
104
+ link.onerror = reject;
105
+ link.onload = () => {
106
+ resolve();
107
+ };
108
+
109
+ document.head.appendChild(link);
110
+
111
+ return link;
112
+ })
113
+ );
114
+
115
+ return Promise.all(promises);
116
+ }
117
+
81
118
  /**
82
119
  * Checks if a key is safe to use in configuration objects to prevent prototype pollution
83
120
  *
@@ -19,7 +19,7 @@ module CKEditor5::Rails
19
19
  delegate :config, to: :@preset
20
20
 
21
21
  def serialize_plugins
22
- (config[:plugins] || []).map { |plugin| Editor::PropsPlugin.normalize(plugin).to_h }.to_json
22
+ (config[:plugins] || []).map { |plugin| Editor::PropsBasePlugin.normalize(plugin).to_h }.to_json
23
23
  end
24
24
 
25
25
  def serialize_config
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'props_plugin'
4
4
  require_relative 'props_inline_plugin'
5
+ require_relative 'props_external_plugin'
5
6
  require_relative 'props'
6
7
 
7
8
  module CKEditor5::Rails::Editor::Helpers
@@ -57,7 +57,7 @@ module CKEditor5::Rails::Editor
57
57
  end
58
58
 
59
59
  def serialize_plugins
60
- (config[:plugins] || []).map { |plugin| PropsPlugin.normalize(plugin).to_h }.to_json
60
+ (config[:plugins] || []).map { |plugin| PropsBasePlugin.normalize(plugin).to_h }.to_json
61
61
  end
62
62
 
63
63
  def serialize_config
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5::Rails::Editor
4
+ class PropsBasePlugin
5
+ attr_reader :name, :assets_bundle
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ end
10
+
11
+ def preload_assets_urls
12
+ []
13
+ end
14
+
15
+ def to_h
16
+ raise NotImplementedError, 'Method #to_h must be implemented in a subclass'
17
+ end
18
+
19
+ def self.normalize(plugin, **kwargs)
20
+ case plugin
21
+ when String, Symbol then PropsPlugin.new(plugin, **kwargs)
22
+ when PropsBasePlugin then plugin
23
+ else raise ArgumentError, "Invalid plugin: #{plugin}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'props_base_plugin'
4
+
5
+ module CKEditor5::Rails::Editor
6
+ class PropsExternalPlugin < PropsBasePlugin
7
+ attr_reader :stylesheets, :js_import_meta
8
+
9
+ def initialize(name, script:, import_as: nil, window_name: nil, stylesheets: [])
10
+ super(name)
11
+
12
+ @stylesheets = stylesheets
13
+ @js_import_meta = CKEditor5::Rails::Assets::JSUrlImportMeta.new(
14
+ script,
15
+ import_name: script,
16
+ import_as: import_as,
17
+ window_name: window_name
18
+ )
19
+ end
20
+
21
+ def preload_assets_urls
22
+ @stylesheets + [@js_import_meta.url]
23
+ end
24
+
25
+ def to_h
26
+ @js_import_meta.to_h.merge(
27
+ type: :external,
28
+ stylesheets: @stylesheets
29
+ )
30
+ end
31
+ end
32
+ end
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'props_base_plugin'
4
+
3
5
  module CKEditor5::Rails::Editor
4
- class PropsInlinePlugin
5
- attr_reader :name, :code
6
+ class PropsInlinePlugin < PropsBasePlugin
7
+ attr_reader :code
6
8
 
7
9
  def initialize(name, code)
8
- @name = name
10
+ super(name)
11
+
9
12
  @code = code
10
13
  validate_code!
11
14
  end
@@ -1,36 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module CKEditor5::Rails::Editor
4
- class PropsPlugin
5
- attr_reader :name, :js_import_meta
3
+ require_relative 'props_base_plugin'
6
4
 
7
- delegate :to_h, to: :import_meta
5
+ module CKEditor5::Rails::Editor
6
+ class PropsPlugin < PropsBasePlugin
7
+ def initialize(name, premium: false, **js_import_meta_attrs)
8
+ super(name)
8
9
 
9
- def initialize(name, premium: false, **js_import_meta)
10
- @name = name
11
- @js_import_meta = if js_import_meta.empty?
12
- { import_name: premium ? 'ckeditor5-premium-features' : 'ckeditor5' }
13
- else
14
- js_import_meta
15
- end
16
- end
10
+ js_import_meta_attrs[:import_name] ||= if premium
11
+ 'ckeditor5-premium-features'
12
+ else
13
+ 'ckeditor5'
14
+ end
17
15
 
18
- def self.normalize(plugin)
19
- case plugin
20
- when String, Symbol then new(plugin)
21
- when PropsPlugin, PropsInlinePlugin then plugin
22
- else raise ArgumentError, "Invalid plugin: #{plugin}"
23
- end
16
+ @js_import_meta = ::CKEditor5::Rails::Assets::JSImportMeta.new(
17
+ import_as: js_import_meta_attrs[:window_name] ? nil : name,
18
+ **js_import_meta_attrs
19
+ )
24
20
  end
25
21
 
26
22
  def to_h
27
- meta = ::CKEditor5::Rails::Assets::JSImportMeta.new(
28
- import_as: js_import_meta[:window_name] ? nil : name,
29
- **js_import_meta
30
- ).to_h
31
-
32
- meta.merge!({ type: :external })
33
- meta
23
+ @js_import_meta.to_h.merge(type: :external)
34
24
  end
35
25
  end
36
26
  end
@@ -4,7 +4,9 @@ require 'rails/engine'
4
4
 
5
5
  require_relative 'presets/manager'
6
6
  require_relative 'hooks/form'
7
+
7
8
  require_relative 'plugins/simple_upload_adapter'
9
+ require_relative 'plugins/wproofreader'
8
10
 
9
11
  module CKEditor5::Rails
10
12
  class Engine < ::Rails::Engine
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../editor/props_external_plugin'
4
+
5
+ module CKEditor5::Rails::Plugins
6
+ class WProofreader < CKEditor5::Rails::Editor::PropsExternalPlugin
7
+ DEFAULT_VERSION = '3.1.2'
8
+ DEFAULT_CDN = 'https://cdn.jsdelivr.net/npm/@webspellchecker/wproofreader-ckeditor5'
9
+
10
+ def initialize(version: nil, cdn: nil)
11
+ cdn ||= DEFAULT_CDN
12
+ version ||= DEFAULT_VERSION
13
+
14
+ script_url = "#{cdn}@#{version}/dist/browser/index.js"
15
+ style_url = "#{cdn}@#{version}/dist/browser/index.css"
16
+
17
+ super(
18
+ :WProofreader,
19
+ script: script_url,
20
+ import_as: 'WProofreader',
21
+ stylesheets: [style_url],
22
+ )
23
+ end
24
+ end
25
+ end
@@ -4,14 +4,25 @@ module CKEditor5::Rails
4
4
  module Presets
5
5
  module Concerns
6
6
  module PluginMethods
7
+ private
8
+
9
+ def register_plugin(plugin_obj)
10
+ config[:plugins] << plugin_obj
11
+ plugin_obj
12
+ end
13
+
14
+ public
15
+
16
+ def external_plugin(name, **kwargs)
17
+ register_plugin(Editor::PropsExternalPlugin.new(name, **kwargs))
18
+ end
19
+
7
20
  def inline_plugin(name, code)
8
- config[:plugins] << Editor::PropsInlinePlugin.new(name, code)
21
+ register_plugin(Editor::PropsInlinePlugin.new(name, code))
9
22
  end
10
23
 
11
24
  def plugin(name, **kwargs)
12
- plugin_obj = PluginsBuilder.create_plugin(name, **kwargs)
13
- config[:plugins] << plugin_obj
14
- plugin_obj
25
+ register_plugin(PluginsBuilder.create_plugin(name, **kwargs))
15
26
  end
16
27
 
17
28
  def plugins(*names, **kwargs, &block)
@@ -9,7 +9,7 @@ module CKEditor5::Rails
9
9
  end
10
10
 
11
11
  def self.create_plugin(name, **kwargs)
12
- if name.is_a?(Editor::PropsInlinePlugin) || name.is_a?(Editor::PropsPlugin)
12
+ if name.is_a?(Editor::PropsBasePlugin)
13
13
  name
14
14
  else
15
15
  Editor::PropsPlugin.new(name, **kwargs)
@@ -204,6 +204,11 @@ module CKEditor5::Rails
204
204
  configure(:simpleUpload, { uploadUrl: upload_url })
205
205
  end
206
206
 
207
+ def wproofreader(version: nil, cdn: nil, **config)
208
+ plugin(Plugins::WProofreader.new(version: version, cdn: cdn))
209
+ configure :wproofreader, config
210
+ end
211
+
207
212
  private
208
213
 
209
214
  def deep_copy_toolbar(toolbar)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CKEditor5
4
4
  module Rails
5
- VERSION = '1.17.3'
5
+ VERSION = '1.18.0'
6
6
 
7
7
  DEFAULT_CKEDITOR_VERSION = '43.3.1'
8
8
  end
@@ -157,6 +157,17 @@ RSpec.describe CKEditor5::Rails::Assets::JSUrlImportMeta do
157
157
  expect(meta).to be_translation
158
158
  end
159
159
  end
160
+
161
+ describe '#to_h' do
162
+ it 'returns hash with url and import meta' do
163
+ meta = described_class.new(url, import_name: 'module', import_as: 'alias')
164
+ expect(meta.to_h).to eq({
165
+ url: url,
166
+ import_name: 'module',
167
+ import_as: 'alias'
168
+ })
169
+ end
170
+ end
160
171
  end
161
172
 
162
173
  RSpec.describe CKEditor5::Rails::Assets::JSImportMeta do
@@ -54,7 +54,7 @@ RSpec.describe CKEditor5::Rails::Context::PresetBuilder do
54
54
  it 'accepts plugin options' do
55
55
  plugin = builder.plugin('Test', premium: true)
56
56
 
57
- expect(plugin.js_import_meta[:import_name]).to eq('ckeditor5-premium-features')
57
+ expect(plugin.to_h[:import_name]).to eq('ckeditor5-premium-features')
58
58
  end
59
59
  end
60
60
 
@@ -82,4 +82,41 @@ RSpec.describe CKEditor5::Rails::Context::PresetBuilder do
82
82
  expect(builder.config[:plugins].map(&:name)).to eq(%w[Test1 Test2])
83
83
  end
84
84
  end
85
+
86
+ describe '#inline_plugin' do
87
+ it 'adds inline plugin to config' do
88
+ plugin = builder.inline_plugin('Test', 'export default class Abc {}')
89
+
90
+ expect(builder.config[:plugins]).to include(plugin)
91
+ expect(plugin).to be_a(CKEditor5::Rails::Editor::PropsInlinePlugin)
92
+ end
93
+
94
+ it 'accepts plugin options' do
95
+ plugin = builder.inline_plugin('Test', 'export default class Abc {}')
96
+
97
+ expect(plugin.code).to eq('export default class Abc {}')
98
+ end
99
+ end
100
+
101
+ describe '#external_plugin' do
102
+ it 'adds external plugin to config' do
103
+ plugin = builder.external_plugin('Test', script: 'https://example.org/script.js')
104
+
105
+ expect(builder.config[:plugins]).to include(plugin)
106
+ expect(plugin).to be_a(CKEditor5::Rails::Editor::PropsExternalPlugin)
107
+ end
108
+
109
+ it 'accepts plugin options' do
110
+ plugin = builder.external_plugin(
111
+ 'Test',
112
+ script: 'https://example.org/script.js',
113
+ import_as: 'ABC',
114
+ stylesheets: ['https://example.org/style.css']
115
+ )
116
+
117
+ expect(plugin.to_h[:import_name]).to eq('https://example.org/script.js')
118
+ expect(plugin.to_h[:import_as]).to eq('ABC')
119
+ expect(plugin.to_h[:stylesheets]).to include('https://example.org/style.css')
120
+ end
121
+ end
85
122
  end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Editor::PropsBasePlugin do
6
+ describe '.normalize' do
7
+ it 'converts string to plugin instance' do
8
+ plugin = described_class.normalize('Bold')
9
+ expect(plugin).to be_a(described_class)
10
+ expect(plugin.name).to eq('Bold')
11
+ end
12
+
13
+ it 'converts symbol to plugin instance' do
14
+ plugin = described_class.normalize(:Bold)
15
+ expect(plugin).to be_a(described_class)
16
+ expect(plugin.name).to eq(:Bold)
17
+ end
18
+
19
+ it 'returns existing plugin instances unchanged' do
20
+ original = described_class.new(:Bold)
21
+ plugin = described_class.normalize(original)
22
+ expect(plugin).to be(original)
23
+ end
24
+
25
+ it 'returns inline plugin instances unchanged' do
26
+ inline = CKEditor5::Rails::Editor::PropsInlinePlugin.new(:Custom, 'export default class {}')
27
+ plugin = described_class.normalize(inline)
28
+ expect(plugin).to be(inline)
29
+ end
30
+
31
+ it 'raises error for invalid input' do
32
+ expect { described_class.normalize({}) }.to raise_error(ArgumentError)
33
+ end
34
+ end
35
+
36
+ describe '#preload_assets_urls' do
37
+ it 'returns empty array' do
38
+ plugin = described_class.new(:Bold)
39
+
40
+ expect(plugin.preload_assets_urls).to eq([])
41
+ end
42
+ end
43
+
44
+ describe '#to_h' do
45
+ it 'raises NotImplementedError' do
46
+ plugin = described_class.new(:Bold)
47
+ expect do
48
+ plugin.to_h
49
+ end.to raise_error(NotImplementedError, 'Method #to_h must be implemented in a subclass')
50
+ end
51
+ end
52
+
53
+ describe '#name' do
54
+ it 'returns the plugin name' do
55
+ plugin = described_class.new(:Bold)
56
+ expect(plugin.name).to eq(:Bold)
57
+ end
58
+
59
+ it 'preserves the type of name argument' do
60
+ string_plugin = described_class.new('Bold')
61
+ symbol_plugin = described_class.new(:Bold)
62
+
63
+ expect(string_plugin.name).to eq('Bold')
64
+ expect(symbol_plugin.name).to eq(:Bold)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Editor::PropsExternalPlugin do
6
+ describe '#initialize' do
7
+ it 'creates plugin with required parameters' do
8
+ plugin = described_class.new('Test', script: 'https://example.org/plugin.js')
9
+
10
+ expect(plugin.name).to eq('Test')
11
+ expect(plugin.preload_assets_urls).to include('https://example.org/plugin.js')
12
+ end
13
+
14
+ it 'accepts optional parameters' do
15
+ plugin = described_class.new(
16
+ 'Test',
17
+ script: 'https://example.org/plugin.js',
18
+ import_as: 'TestPlugin',
19
+ window_name: 'TestWindow',
20
+ stylesheets: ['https://example.org/style.css']
21
+ )
22
+
23
+ expect(plugin.preload_assets_urls).to include('https://example.org/style.css')
24
+ end
25
+ end
26
+
27
+ describe '#preload_assets_urls' do
28
+ it 'returns array with script and stylesheets urls' do
29
+ plugin = described_class.new(
30
+ 'Test',
31
+ script: 'https://example.org/plugin.js',
32
+ stylesheets: ['https://example.org/style1.css', 'https://example.org/style2.css']
33
+ )
34
+
35
+ expect(plugin.preload_assets_urls).to eq([
36
+ 'https://example.org/style1.css',
37
+ 'https://example.org/style2.css',
38
+ 'https://example.org/plugin.js'
39
+ ])
40
+ end
41
+ end
42
+
43
+ describe '#to_h' do
44
+ it 'returns hash with plugin configuration' do
45
+ plugin = described_class.new(
46
+ 'Test',
47
+ script: 'https://example.org/plugin.js',
48
+ import_as: 'TestPlugin',
49
+ window_name: 'TestWindow',
50
+ stylesheets: ['https://example.org/style.css']
51
+ )
52
+
53
+ expect(plugin.to_h).to include(
54
+ type: :external,
55
+ import_name: 'https://example.org/plugin.js',
56
+ import_as: 'TestPlugin',
57
+ window_name: 'TestWindow',
58
+ stylesheets: ['https://example.org/style.css']
59
+ )
60
+ end
61
+ end
62
+ end
@@ -3,36 +3,6 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe CKEditor5::Rails::Editor::PropsPlugin do
6
- describe '.normalize' do
7
- it 'converts string to plugin instance' do
8
- plugin = described_class.normalize('Bold')
9
- expect(plugin).to be_a(described_class)
10
- expect(plugin.name).to eq('Bold')
11
- end
12
-
13
- it 'converts symbol to plugin instance' do
14
- plugin = described_class.normalize(:Bold)
15
- expect(plugin).to be_a(described_class)
16
- expect(plugin.name).to eq(:Bold)
17
- end
18
-
19
- it 'returns existing plugin instances unchanged' do
20
- original = described_class.new(:Bold)
21
- plugin = described_class.normalize(original)
22
- expect(plugin).to be(original)
23
- end
24
-
25
- it 'returns inline plugin instances unchanged' do
26
- inline = CKEditor5::Rails::Editor::PropsInlinePlugin.new(:Custom, 'export default class {}')
27
- plugin = described_class.normalize(inline)
28
- expect(plugin).to be(inline)
29
- end
30
-
31
- it 'raises error for invalid input' do
32
- expect { described_class.normalize({}) }.to raise_error(ArgumentError)
33
- end
34
- end
35
-
36
6
  describe '#to_h' do
37
7
  it 'generates hash for standard plugin' do
38
8
  plugin = described_class.new(:Bold)
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe CKEditor5::Rails::Plugins::WProofreader do
6
+ let(:default_cdn) { 'https://cdn.jsdelivr.net/npm/@webspellchecker/wproofreader-ckeditor5' }
7
+ let(:default_version) { '3.1.2' }
8
+
9
+ describe '#initialize' do
10
+ context 'with default parameters' do
11
+ subject(:plugin) { described_class.new }
12
+
13
+ it 'has correct name' do
14
+ expect(plugin.name).to eq(:WProofreader)
15
+ end
16
+
17
+ it 'returns correct preload assets urls' do
18
+ expected_urls = [
19
+ "#{default_cdn}@#{default_version}/dist/browser/index.css",
20
+ "#{default_cdn}@#{default_version}/dist/browser/index.js"
21
+ ]
22
+ expect(plugin.preload_assets_urls).to eq(expected_urls)
23
+ end
24
+
25
+ it 'returns correct hash representation' do
26
+ expected_hash = {
27
+ type: :external,
28
+ stylesheets: ["#{default_cdn}@#{default_version}/dist/browser/index.css"],
29
+ url: "#{default_cdn}@#{default_version}/dist/browser/index.js",
30
+ import_name: "#{default_cdn}@#{default_version}/dist/browser/index.js",
31
+ import_as: 'WProofreader'
32
+ }
33
+ expect(plugin.to_h).to eq(expected_hash)
34
+ end
35
+ end
36
+
37
+ context 'with custom parameters' do
38
+ let(:custom_cdn) { 'https://custom-cdn.com/wproofreader' }
39
+ let(:custom_version) { '4.0.0' }
40
+ subject(:plugin) { described_class.new(version: custom_version, cdn: custom_cdn) }
41
+
42
+ it 'returns correct preload assets urls with custom CDN' do
43
+ expected_urls = [
44
+ "#{custom_cdn}@#{custom_version}/dist/browser/index.css",
45
+ "#{custom_cdn}@#{custom_version}/dist/browser/index.js"
46
+ ]
47
+ expect(plugin.preload_assets_urls).to eq(expected_urls)
48
+ end
49
+
50
+ it 'returns correct hash representation with custom CDN' do
51
+ expected_hash = {
52
+ type: :external,
53
+ stylesheets: ["#{custom_cdn}@#{custom_version}/dist/browser/index.css"],
54
+ url: "#{custom_cdn}@#{custom_version}/dist/browser/index.js",
55
+ import_name: "#{custom_cdn}@#{custom_version}/dist/browser/index.js",
56
+ import_as: 'WProofreader'
57
+ }
58
+ expect(plugin.to_h).to eq(expected_hash)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -380,4 +380,22 @@ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
380
380
  end
381
381
  end
382
382
  end
383
+
384
+ describe 'wproofreader' do
385
+ it 'configures WProofreader plugin' do
386
+ builder.wproofreader(version: '1.0.0', cdn: 'https://cdn.example.com')
387
+ plugin = builder.config[:plugins].first
388
+
389
+ expect(plugin).to be_a(CKEditor5::Rails::Editor::PropsExternalPlugin)
390
+ expect(plugin.name).to eq(:WProofreader)
391
+ expect(plugin.to_h[:import_name]).to eq('https://cdn.example.com@1.0.0/dist/browser/index.js')
392
+ expect(plugin.to_h[:stylesheets]).to eq(['https://cdn.example.com@1.0.0/dist/browser/index.css'])
393
+ end
394
+
395
+ it 'sets proper editor configuration in wproofreader key' do
396
+ builder.wproofreader(version: '1.0.0', cdn: 'https://cdn.example.com', language: 'en')
397
+
398
+ expect(builder.config[:wproofreader]).to eq({ language: 'en' })
399
+ end
400
+ end
383
401
  end
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.17.3
4
+ version: 1.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mateusz Bagiński
@@ -63,6 +63,8 @@ files:
63
63
  - lib/ckeditor5/rails/editor/helpers/config_helpers.rb
64
64
  - lib/ckeditor5/rails/editor/helpers/editor_helpers.rb
65
65
  - lib/ckeditor5/rails/editor/props.rb
66
+ - lib/ckeditor5/rails/editor/props_base_plugin.rb
67
+ - lib/ckeditor5/rails/editor/props_external_plugin.rb
66
68
  - lib/ckeditor5/rails/editor/props_inline_plugin.rb
67
69
  - lib/ckeditor5/rails/editor/props_plugin.rb
68
70
  - lib/ckeditor5/rails/engine.rb
@@ -70,6 +72,7 @@ files:
70
72
  - lib/ckeditor5/rails/hooks/form.rb
71
73
  - lib/ckeditor5/rails/hooks/simple_form.rb
72
74
  - lib/ckeditor5/rails/plugins/simple_upload_adapter.rb
75
+ - lib/ckeditor5/rails/plugins/wproofreader.rb
73
76
  - lib/ckeditor5/rails/presets/concerns/configuration_methods.rb
74
77
  - lib/ckeditor5/rails/presets/concerns/plugin_methods.rb
75
78
  - lib/ckeditor5/rails/presets/manager.rb
@@ -98,12 +101,15 @@ files:
98
101
  - spec/lib/ckeditor5/rails/editor/editable_height_normalizer_spec.rb
99
102
  - spec/lib/ckeditor5/rails/editor/helpers/config_helpers_spec.rb
100
103
  - spec/lib/ckeditor5/rails/editor/helpers/editor_helpers_spec.rb
104
+ - spec/lib/ckeditor5/rails/editor/props_base_plugin_spec.rb
105
+ - spec/lib/ckeditor5/rails/editor/props_external_plugin_spec.rb
101
106
  - spec/lib/ckeditor5/rails/editor/props_inline_plugin_spec.rb
102
107
  - spec/lib/ckeditor5/rails/editor/props_plugin_spec.rb
103
108
  - spec/lib/ckeditor5/rails/editor/props_spec.rb
104
109
  - spec/lib/ckeditor5/rails/engine_spec.rb
105
110
  - spec/lib/ckeditor5/rails/hooks/form_spec.rb
106
111
  - spec/lib/ckeditor5/rails/hooks/simple_form_spec.rb
112
+ - spec/lib/ckeditor5/rails/plugins/wproofreader_spec.rb
107
113
  - spec/lib/ckeditor5/rails/presets/manager_spec.rb
108
114
  - spec/lib/ckeditor5/rails/presets/plugins_builder_spec.rb
109
115
  - spec/lib/ckeditor5/rails/presets/preset_builder_spec.rb
@@ -116,7 +122,11 @@ files:
116
122
  homepage: https://github.com/Mati365/ckeditor5-rails
117
123
  licenses:
118
124
  - GPL-2.0
119
- metadata: {}
125
+ metadata:
126
+ homepage_uri: https://github.com/Mati365/ckeditor5-rails
127
+ documentation_uri: https://github.com/Mati365/ckeditor5-rails
128
+ source_code_uri: https://github.com/Mati365/ckeditor5-rails
129
+ bug_tracker_uri: https://github.com/Mati365/ckeditor5-rails/issues
120
130
  post_install_message:
121
131
  rdoc_options: []
122
132
  require_paths:
@@ -156,12 +166,15 @@ test_files:
156
166
  - spec/lib/ckeditor5/rails/editor/editable_height_normalizer_spec.rb
157
167
  - spec/lib/ckeditor5/rails/editor/helpers/config_helpers_spec.rb
158
168
  - spec/lib/ckeditor5/rails/editor/helpers/editor_helpers_spec.rb
169
+ - spec/lib/ckeditor5/rails/editor/props_base_plugin_spec.rb
170
+ - spec/lib/ckeditor5/rails/editor/props_external_plugin_spec.rb
159
171
  - spec/lib/ckeditor5/rails/editor/props_inline_plugin_spec.rb
160
172
  - spec/lib/ckeditor5/rails/editor/props_plugin_spec.rb
161
173
  - spec/lib/ckeditor5/rails/editor/props_spec.rb
162
174
  - spec/lib/ckeditor5/rails/engine_spec.rb
163
175
  - spec/lib/ckeditor5/rails/hooks/form_spec.rb
164
176
  - spec/lib/ckeditor5/rails/hooks/simple_form_spec.rb
177
+ - spec/lib/ckeditor5/rails/plugins/wproofreader_spec.rb
165
178
  - spec/lib/ckeditor5/rails/presets/manager_spec.rb
166
179
  - spec/lib/ckeditor5/rails/presets/plugins_builder_spec.rb
167
180
  - spec/lib/ckeditor5/rails/presets/preset_builder_spec.rb