ckeditor5 1.20.1 → 1.21.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 +66 -2
- data/lib/ckeditor5/rails/assets/assets_bundle.rb +11 -1
- data/lib/ckeditor5/rails/assets/assets_bundle_html_serializer.rb +5 -10
- data/lib/ckeditor5/rails/assets/webcomponent_bundle.rb +10 -3
- data/lib/ckeditor5/rails/assets/webcomponents/components/editor.mjs +35 -2
- data/lib/ckeditor5/rails/assets/webcomponents/utils.mjs +36 -2
- data/lib/ckeditor5/rails/cdn/concerns/bundle_builder.rb +57 -0
- data/lib/ckeditor5/rails/cdn/helpers.rb +62 -55
- data/lib/ckeditor5/rails/editor/helpers/editor_helpers.rb +25 -19
- data/lib/ckeditor5/rails/editor/props.rb +7 -14
- data/lib/ckeditor5/rails/engine.rb +13 -0
- data/lib/ckeditor5/rails/presets/manager.rb +2 -0
- data/lib/ckeditor5/rails/presets/preset_builder.rb +1 -1
- data/lib/ckeditor5/rails/version.rb +1 -1
- data/spec/e2e/features/ajax_form_integration_spec.rb +78 -0
- data/spec/e2e/features/lazy_assets_spec.rb +54 -0
- data/spec/e2e/support/form_helpers.rb +4 -1
- data/spec/lib/ckeditor5/rails/assets/assets_bundle_hml_serializer_spec.rb +53 -0
- data/spec/lib/ckeditor5/rails/assets/assets_bundle_spec.rb +2 -1
- data/spec/lib/ckeditor5/rails/cdn/helpers_spec.rb +95 -3
- data/spec/lib/ckeditor5/rails/editor/helpers/editor_helpers_spec.rb +85 -25
- data/spec/lib/ckeditor5/rails/editor/props_spec.rb +14 -34
- data/spec/lib/ckeditor5/rails/engine_spec.rb +10 -0
- data/spec/lib/ckeditor5/rails/hooks/form_spec.rb +15 -2
- data/spec/lib/ckeditor5/rails/plugins/wproofreader_spec.rb +2 -0
- data/spec/lib/ckeditor5/rails/version_detector_spec.rb +1 -1
- metadata +7 -2
@@ -14,16 +14,17 @@ module CKEditor5::Rails::Editor
|
|
14
14
|
}.freeze
|
15
15
|
|
16
16
|
def initialize(
|
17
|
-
|
18
|
-
|
17
|
+
type, config,
|
18
|
+
bundle: nil,
|
19
|
+
watchdog: true,
|
20
|
+
editable_height: nil
|
19
21
|
)
|
20
22
|
raise ArgumentError, "Invalid editor type: #{type}" unless Props.valid_editor_type?(type)
|
21
23
|
|
22
|
-
@
|
24
|
+
@bundle = bundle
|
23
25
|
@watchdog = watchdog
|
24
26
|
@type = type
|
25
27
|
@config = config
|
26
|
-
@language = language
|
27
28
|
@editable_height = EditableHeightNormalizer.new(type).normalize(editable_height)
|
28
29
|
end
|
29
30
|
|
@@ -40,11 +41,11 @@ module CKEditor5::Rails::Editor
|
|
40
41
|
|
41
42
|
private
|
42
43
|
|
43
|
-
attr_reader :
|
44
|
+
attr_reader :bundle, :watchdog, :type, :config, :editable_height
|
44
45
|
|
45
46
|
def serialized_attributes
|
46
47
|
{
|
47
|
-
|
48
|
+
bundle: bundle.to_json,
|
48
49
|
plugins: serialize_plugins,
|
49
50
|
config: serialize_config,
|
50
51
|
watchdog: watchdog
|
@@ -52,10 +53,6 @@ module CKEditor5::Rails::Editor
|
|
52
53
|
.merge(editable_height ? { 'editable-height' => editable_height } : {})
|
53
54
|
end
|
54
55
|
|
55
|
-
def serialize_translations
|
56
|
-
controller_context[:bundle]&.translations_scripts&.map(&:to_h).to_json || '[]'
|
57
|
-
end
|
58
|
-
|
59
56
|
def serialize_plugins
|
60
57
|
(config[:plugins] || []).map { |plugin| PropsBasePlugin.normalize(plugin).to_h }.to_json
|
61
58
|
end
|
@@ -63,10 +60,6 @@ module CKEditor5::Rails::Editor
|
|
63
60
|
def serialize_config
|
64
61
|
config
|
65
62
|
.except(:plugins)
|
66
|
-
.tap do |cfg|
|
67
|
-
cfg[:licenseKey] = controller_context[:license_key] if controller_context[:license_key]
|
68
|
-
cfg[:language] = { ui: @language } if @language
|
69
|
-
end
|
70
63
|
.to_json
|
71
64
|
end
|
72
65
|
end
|
@@ -7,6 +7,8 @@ require_relative 'plugins/simple_upload_adapter'
|
|
7
7
|
require_relative 'plugins/wproofreader'
|
8
8
|
|
9
9
|
module CKEditor5::Rails
|
10
|
+
class PresetNotFoundError < ArgumentError; end
|
11
|
+
|
10
12
|
class Engine < ::Rails::Engine
|
11
13
|
config.ckeditor5 = ActiveSupport::OrderedOptions.new
|
12
14
|
config.ckeditor5.presets = Presets::Manager.new
|
@@ -47,6 +49,10 @@ module CKEditor5::Rails
|
|
47
49
|
config.ckeditor5.presets.default
|
48
50
|
end
|
49
51
|
|
52
|
+
def presets
|
53
|
+
config.ckeditor5.presets
|
54
|
+
end
|
55
|
+
|
50
56
|
def configure(&block)
|
51
57
|
proxy = ConfigurationProxy.new(config.ckeditor5)
|
52
58
|
proxy.instance_eval(&block)
|
@@ -57,6 +63,13 @@ module CKEditor5::Rails
|
|
57
63
|
|
58
64
|
base.presets[preset]
|
59
65
|
end
|
66
|
+
|
67
|
+
def find_preset!(preset)
|
68
|
+
found_preset = find_preset(preset)
|
69
|
+
return found_preset if found_preset.present?
|
70
|
+
|
71
|
+
raise PresetNotFoundError, "Preset '#{preset}' not found. Please define it in the initializer."
|
72
|
+
end
|
60
73
|
end
|
61
74
|
|
62
75
|
class ConfigurationProxy
|
@@ -86,7 +86,7 @@ module CKEditor5::Rails
|
|
86
86
|
# Merge preset with configuration hash
|
87
87
|
# @param overrides [Hash] Configuration options to merge
|
88
88
|
# @return [self]
|
89
|
-
def merge_with_hash!(**overrides)
|
89
|
+
def merge_with_hash!(**overrides)
|
90
90
|
@version = Semver.new(overrides[:version]) if overrides.key?(:version)
|
91
91
|
@premium = overrides.fetch(:premium, premium)
|
92
92
|
@cdn = overrides.fetch(:cdn, cdn)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'e2e/spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'AJAX Form Integration', type: :feature, js: true do
|
6
|
+
before do
|
7
|
+
visit('form_ajax')
|
8
|
+
setup_form_tracking(page)
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_examples 'an ajax form with CKEditor' do |form_testid, editor_testid, submit_testid, response_id| # rubocop:disable Metrics/BlockLength
|
12
|
+
let(:form) { find("[data-testid='#{form_testid}']") }
|
13
|
+
let(:editor) { find("[data-testid='#{editor_testid}']") }
|
14
|
+
let(:editable) { editor.find('.ck-editor__editable') }
|
15
|
+
let(:text_field) { editor.find('textarea', visible: :hidden) }
|
16
|
+
let(:submit_button) { find("[data-testid='#{submit_testid}']") }
|
17
|
+
let(:response_container) { find("##{response_id}") }
|
18
|
+
|
19
|
+
before do
|
20
|
+
expect(page).to have_css('.ck-editor__editable', wait: 10)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'loads editor properly' do
|
24
|
+
expect(page).to have_css("[data-testid='#{editor_testid}'] .ck-editor__editable")
|
25
|
+
expect(editor).to have_invisible_textarea
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'validates required fields' do
|
29
|
+
editable.click
|
30
|
+
editable.send_keys([[:control, 'a'], :backspace])
|
31
|
+
text_field.set('')
|
32
|
+
submit_button.click
|
33
|
+
|
34
|
+
expect(form).not_to have_been_submitted
|
35
|
+
expect(text_field).to be_invalid
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'submits form and shows response' do
|
39
|
+
test_content = "Test content #{Time.now.to_i}"
|
40
|
+
|
41
|
+
editable.click
|
42
|
+
editable.send_keys([[:control, 'a'], :backspace])
|
43
|
+
editable.send_keys(test_content)
|
44
|
+
|
45
|
+
sleep 1
|
46
|
+
|
47
|
+
submit_button.click
|
48
|
+
|
49
|
+
eventually(timeout: 13) do
|
50
|
+
expect(response_container).to be_visible
|
51
|
+
expect(response_container).to have_text('Success!')
|
52
|
+
expect(response_container).to have_text(test_content)
|
53
|
+
|
54
|
+
# Verify that CKEditor initializes in the response
|
55
|
+
response_editor = response_container.find('.ck-editor__editable', wait: 10)
|
56
|
+
|
57
|
+
expect(response_editor).to be_visible
|
58
|
+
expect(response_editor).to have_text(test_content)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'Regular AJAX form' do
|
64
|
+
it_behaves_like 'an ajax form with CKEditor',
|
65
|
+
'rails-form',
|
66
|
+
'rails-form-editor',
|
67
|
+
'rails-form-submit',
|
68
|
+
'response'
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'Turbo Stream form' do
|
72
|
+
it_behaves_like 'an ajax form with CKEditor',
|
73
|
+
'rails-form-stream',
|
74
|
+
'rails-form-editor-stream',
|
75
|
+
'rails-form-submit-stream',
|
76
|
+
'response-stream'
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'e2e/spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'Lazy Assets', type: :feature do
|
6
|
+
context 'without JavaScript', js: false do
|
7
|
+
before do
|
8
|
+
visit 'classic_lazy_assets?no_embed=true'
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'does not load CKEditor assets' do
|
12
|
+
expect(page).not_to have_css('link[href*="ckeditor5"]', visible: false)
|
13
|
+
expect(page).not_to have_css('script[src*="ckeditor5"]', visible: false)
|
14
|
+
|
15
|
+
scripts = page.all('script:not([type="importmap"]):not([type="module"])', visible: false)
|
16
|
+
external_scripts = scripts.reject { |s| s[:src].nil? }
|
17
|
+
expect(external_scripts).not_to include(match(/ckeditor5/))
|
18
|
+
|
19
|
+
expect(page).to have_css('script[type="importmap"]', visible: false)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with JavaScript', js: true do
|
24
|
+
before { visit 'classic_lazy_assets' }
|
25
|
+
|
26
|
+
it 'loads editor when needed' do
|
27
|
+
expect(page).to have_css('.ck-editor__editable', wait: 10)
|
28
|
+
expect(page).to have_css('link[href*="ckeditor5"]', visible: false)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'initializes editor properly' do
|
32
|
+
editor = find('.ck-editor__editable')
|
33
|
+
expect(editor).to be_visible
|
34
|
+
|
35
|
+
editor.click
|
36
|
+
editor.send_keys('Test content')
|
37
|
+
|
38
|
+
expect(editor).to have_text('Test content')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'supports multiple editor instances' do
|
42
|
+
visit 'classic_lazy_assets?multiple=true'
|
43
|
+
|
44
|
+
editors = all('.ck-editor__editable', wait: 10)
|
45
|
+
expect(editors.length).to eq(2)
|
46
|
+
|
47
|
+
editors.each do |editor|
|
48
|
+
editor.click
|
49
|
+
editor.send_keys('Content for editor')
|
50
|
+
expect(editor).to have_text('Content for editor')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -6,7 +6,10 @@ module FormHelpers
|
|
6
6
|
window.lastSubmittedForm = null;
|
7
7
|
|
8
8
|
document.addEventListener('submit', (e) => {
|
9
|
-
e.
|
9
|
+
if (!e.target.hasAttribute('data-turbo-frame')) {
|
10
|
+
e.preventDefault();
|
11
|
+
}
|
12
|
+
|
10
13
|
window.lastSubmittedForm = e.target.id;
|
11
14
|
});
|
12
15
|
JS
|
@@ -138,6 +138,59 @@ RSpec.describe CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer do
|
|
138
138
|
nonce: 'true'
|
139
139
|
})
|
140
140
|
end
|
141
|
+
|
142
|
+
context 'with lazy loading' do
|
143
|
+
subject(:html) { described_class.new(bundle, lazy: true).to_html }
|
144
|
+
|
145
|
+
it 'does not include preload tags' do
|
146
|
+
expect(html).not_to have_tag('link', with: { rel: 'preload' })
|
147
|
+
expect(html).not_to have_tag('link', with: { rel: 'modulepreload' })
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'does not include stylesheet links' do
|
151
|
+
stylesheets.each do |url|
|
152
|
+
expect(html).not_to have_tag('link', with: { href: url, rel: 'stylesheet' })
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'does not include window script tags' do
|
157
|
+
scripts.each do |script|
|
158
|
+
expect(html).not_to have_tag('script', with: { src: script.url }) if script.window?
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'includes web component script' do
|
163
|
+
expect(html).to have_tag('script', with: { type: 'module' })
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'with eager loading (lazy: false)' do
|
168
|
+
subject(:html) { described_class.new(bundle, lazy: false).to_html }
|
169
|
+
|
170
|
+
it 'includes preload tags' do
|
171
|
+
scripts.each do |script|
|
172
|
+
expect(html).to have_tag('link', with: {
|
173
|
+
href: script.url,
|
174
|
+
rel: script.esm? ? 'modulepreload' : 'preload'
|
175
|
+
})
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'includes stylesheet links' do
|
180
|
+
stylesheets.each do |url|
|
181
|
+
expect(html).to have_tag('link', with: {
|
182
|
+
href: url,
|
183
|
+
rel: 'stylesheet'
|
184
|
+
})
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'includes window script tags' do
|
189
|
+
scripts.each do |script|
|
190
|
+
expect(html).to have_tag('script', with: { src: script.url }) if script.window?
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
141
194
|
end
|
142
195
|
|
143
196
|
describe '.url_resource_preload_type' do
|
@@ -35,10 +35,15 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
before do
|
38
|
-
allow(CKEditor5::Rails::Engine).to receive(:find_preset).and_return(preset)
|
38
|
+
allow(CKEditor5::Rails::Engine).to receive(:find_preset!).and_return(preset)
|
39
39
|
allow(CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer).to receive(:new).and_return(serializer)
|
40
40
|
end
|
41
41
|
|
42
|
+
after do
|
43
|
+
RSpec::Mocks.space.proxy_for(CKEditor5::Rails::Engine).reset
|
44
|
+
RSpec::Mocks.space.proxy_for(CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer).reset
|
45
|
+
end
|
46
|
+
|
42
47
|
describe '#ckeditor5_assets' do
|
43
48
|
context 'with valid preset' do
|
44
49
|
it 'creates base bundle' do
|
@@ -206,12 +211,13 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
|
|
206
211
|
|
207
212
|
context 'destructure non-matching preset override' do
|
208
213
|
before do
|
209
|
-
|
214
|
+
RSpec::Mocks.space.proxy_for(CKEditor5::Rails::Engine).reset
|
210
215
|
end
|
211
216
|
|
212
217
|
it 'raises error' do
|
213
218
|
expect { helper.ckeditor5_assets(preset: :invalid) }
|
214
|
-
.to raise_error(
|
219
|
+
.to raise_error(CKEditor5::Rails::PresetNotFoundError)
|
220
|
+
RSpec::Mocks.space.proxy_for(CKEditor5::Rails::Engine).reset
|
215
221
|
end
|
216
222
|
end
|
217
223
|
|
@@ -256,6 +262,92 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
|
|
256
262
|
end
|
257
263
|
end
|
258
264
|
|
265
|
+
describe '#ckeditor5_lazy_javascript_tags' do
|
266
|
+
let(:web_component_html) do
|
267
|
+
'<script type="module" src="web-component.js">web component code</script>'.html_safe
|
268
|
+
end
|
269
|
+
|
270
|
+
let(:import_map_html) { '<script type="importmap">{"imports":{}}</script>'.html_safe }
|
271
|
+
|
272
|
+
let(:web_component_bundle) do
|
273
|
+
instance_double(CKEditor5::Rails::Assets::WebComponentBundle, to_html: web_component_html)
|
274
|
+
end
|
275
|
+
let(:import_map_bundle) do
|
276
|
+
instance_double(CKEditor5::Rails::Assets::AssetsImportMap, to_html: import_map_html)
|
277
|
+
end
|
278
|
+
let(:preset_manager) { instance_double(CKEditor5::Rails::Presets::Manager) }
|
279
|
+
let(:test_preset1) { instance_double(CKEditor5::Rails::Presets::PresetBuilder) }
|
280
|
+
let(:test_preset2) { instance_double(CKEditor5::Rails::Presets::PresetBuilder) }
|
281
|
+
|
282
|
+
before do
|
283
|
+
allow(CKEditor5::Rails::Assets::WebComponentBundle).to receive(:instance).and_return(
|
284
|
+
web_component_bundle
|
285
|
+
)
|
286
|
+
|
287
|
+
allow(CKEditor5::Rails::Assets::AssetsImportMap).to receive(:new).and_return(
|
288
|
+
import_map_bundle
|
289
|
+
)
|
290
|
+
|
291
|
+
allow(CKEditor5::Rails::Engine).to receive(:presets).and_return(preset_manager)
|
292
|
+
allow(preset_manager).to receive(:to_h).and_return({
|
293
|
+
test1: test_preset1,
|
294
|
+
test2: test_preset2
|
295
|
+
})
|
296
|
+
|
297
|
+
allow(helper).to receive(:create_preset_bundle).with(test_preset1)
|
298
|
+
.and_return(CKEditor5::Rails::Assets::AssetsBundle.new(
|
299
|
+
scripts: ['test1.js']
|
300
|
+
))
|
301
|
+
|
302
|
+
allow(helper).to receive(:create_preset_bundle).with(test_preset2)
|
303
|
+
.and_return(CKEditor5::Rails::Assets::AssetsBundle.new(
|
304
|
+
scripts: ['test2.js']
|
305
|
+
))
|
306
|
+
end
|
307
|
+
|
308
|
+
context 'when importmap is available' do
|
309
|
+
before do
|
310
|
+
allow(helper).to receive(:importmap_available?).and_return(true)
|
311
|
+
allow(helper).to receive(:importmap_rendered?).and_return(false)
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'stores bundle in context and returns web component script' do
|
315
|
+
result = helper.ckeditor5_lazy_javascript_tags
|
316
|
+
|
317
|
+
expect(result).to have_tag('script', with: {
|
318
|
+
type: 'module',
|
319
|
+
src: 'web-component.js'
|
320
|
+
})
|
321
|
+
expect(context[:bundle].scripts).to match_array(['test1.js', 'test2.js'])
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'raises error when importmap is already rendered' do
|
325
|
+
allow(helper).to receive(:importmap_rendered?).and_return(true)
|
326
|
+
|
327
|
+
expect { helper.ckeditor5_lazy_javascript_tags }
|
328
|
+
.to raise_error(CKEditor5::Rails::Cdn::Helpers::ImportmapAlreadyRenderedError)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
context 'when importmap is not available' do
|
333
|
+
before do
|
334
|
+
allow(helper).to receive(:importmap_available?).and_return(false)
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'returns both importmap and web component scripts as one string' do
|
338
|
+
result = helper.ckeditor5_lazy_javascript_tags
|
339
|
+
|
340
|
+
expect(result).to have_tag('script', with: { type: 'importmap' },
|
341
|
+
text: '{"imports":{}}')
|
342
|
+
|
343
|
+
expect(result).to have_tag('script', with: {
|
344
|
+
type: 'module',
|
345
|
+
src: 'web-component.js'
|
346
|
+
})
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
259
351
|
describe 'cdn helper methods' do
|
260
352
|
it 'generates helper methods for third-party CDNs' do
|
261
353
|
expect(helper).to respond_to(:ckeditor5_unpkg_assets)
|
@@ -16,30 +16,69 @@ RSpec.describe CKEditor5::Rails::Editor::Helpers::Editor do
|
|
16
16
|
let(:context) { { preset: :default, cdn: :jsdelivr } }
|
17
17
|
|
18
18
|
before do
|
19
|
+
RSpec::Mocks.space.proxy_for(CKEditor5::Rails::Engine).reset
|
20
|
+
|
19
21
|
helper.instance_variable_set(:@__ckeditor_context, context)
|
22
|
+
|
20
23
|
allow(preset).to receive(:type).and_return(:classic)
|
21
24
|
allow(preset).to receive(:config).and_return({})
|
22
25
|
allow(preset).to receive(:automatic_upgrades?).and_return(false)
|
26
|
+
allow(preset).to receive(:editable_height).and_return(nil)
|
23
27
|
end
|
24
28
|
|
25
|
-
|
29
|
+
before do
|
30
|
+
test_class.send(:public, :ckeditor5_context_or_fallback)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#ckeditor5_context_or_fallback' do
|
26
34
|
before do
|
27
|
-
|
35
|
+
if helper.instance_variable_defined?(:@__ckeditor_context)
|
36
|
+
helper.remove_instance_variable(:@__ckeditor_context)
|
37
|
+
end
|
28
38
|
end
|
29
39
|
|
30
|
-
it '
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
)
|
40
|
+
it 'returns existing context when available' do
|
41
|
+
context = { preset: :custom, bundle: 'custom-bundle' }
|
42
|
+
helper.instance_variable_set(:@__ckeditor_context, context)
|
43
|
+
|
44
|
+
expect(helper.ckeditor5_context_or_fallback(nil)).to eq(context)
|
36
45
|
end
|
37
46
|
|
38
|
-
it '
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
47
|
+
it 'creates context from preset when provided' do
|
48
|
+
custom_preset = instance_double(CKEditor5::Rails::Presets::PresetBuilder)
|
49
|
+
|
50
|
+
allow(CKEditor5::Rails::Engine).to receive(:find_preset)
|
51
|
+
.with(:custom)
|
52
|
+
.and_return(custom_preset)
|
53
|
+
|
54
|
+
allow(helper).to receive(:create_preset_bundle)
|
55
|
+
.with(custom_preset)
|
56
|
+
.and_return('custom-bundle')
|
57
|
+
|
58
|
+
result = helper.ckeditor5_context_or_fallback(:custom)
|
59
|
+
expect(result).to match({
|
60
|
+
bundle: 'custom-bundle',
|
61
|
+
preset: custom_preset
|
62
|
+
})
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns fallback context when no context or preset is available' do
|
66
|
+
RSpec::Mocks.space.proxy_for(CKEditor5::Rails::Engine).reset
|
67
|
+
|
68
|
+
allow(CKEditor5::Rails::Engine).to receive(:default_preset)
|
69
|
+
.and_return(:default)
|
70
|
+
|
71
|
+
result = helper.ckeditor5_context_or_fallback(nil)
|
72
|
+
expect(result).to match({
|
73
|
+
bundle: nil,
|
74
|
+
preset: :default
|
75
|
+
})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#ckeditor5_editor' do
|
80
|
+
before do
|
81
|
+
allow(CKEditor5::Rails::Engine).to receive(:find_preset).with(:default).and_return(preset)
|
43
82
|
end
|
44
83
|
|
45
84
|
it 'merges extra configuration with preset config' do
|
@@ -124,10 +163,6 @@ RSpec.describe CKEditor5::Rails::Editor::Helpers::Editor do
|
|
124
163
|
end
|
125
164
|
|
126
165
|
context 'when using preset lookup' do
|
127
|
-
before do
|
128
|
-
RSpec::Mocks.space.proxy_for(helper).remove_stub(:find_preset)
|
129
|
-
end
|
130
|
-
|
131
166
|
it 'uses default preset when none specified' do
|
132
167
|
expect(CKEditor5::Rails::Engine).to receive(:find_preset)
|
133
168
|
.with(:default)
|
@@ -154,15 +189,40 @@ RSpec.describe CKEditor5::Rails::Editor::Helpers::Editor do
|
|
154
189
|
helper.ckeditor5_editor(preset: :explicit)
|
155
190
|
end
|
156
191
|
|
157
|
-
it 'raises error when preset
|
158
|
-
allow(CKEditor5::Rails::Engine).to receive(:find_preset)
|
159
|
-
|
160
|
-
.
|
192
|
+
it 'raises error when preset is not found' do
|
193
|
+
allow(CKEditor5::Rails::Engine).to receive(:find_preset).with(:unknown).and_return(nil)
|
194
|
+
expect do
|
195
|
+
helper.ckeditor5_editor(preset: :unknown)
|
196
|
+
end.to raise_error(CKEditor5::Rails::PresetNotFoundError)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'uses context from ckeditor5_context_or_fallback' do
|
201
|
+
custom_context = { preset: :custom, bundle: 'custom-bundle' }
|
202
|
+
allow(helper).to receive(:ckeditor5_context_or_fallback)
|
203
|
+
.with(nil)
|
204
|
+
.and_return(custom_context)
|
205
|
+
|
206
|
+
allow(CKEditor5::Rails::Engine).to receive(:find_preset)
|
207
|
+
.with(:custom)
|
208
|
+
.and_return(preset)
|
209
|
+
|
210
|
+
helper.ckeditor5_editor
|
211
|
+
end
|
212
|
+
|
213
|
+
context 'when using editable height' do
|
214
|
+
it 'uses editable height from preset when not explicitly provided' do
|
215
|
+
allow(preset).to receive(:editable_height).and_return(400)
|
216
|
+
|
217
|
+
expect(helper.ckeditor5_editor).to include('editable-height="400px"')
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'uses editable height from options when provided' do
|
221
|
+
expect(helper.ckeditor5_editor(editable_height: 500)).to include('editable-height="500px"')
|
222
|
+
|
223
|
+
allow(preset).to receive(:editable_height).and_return(700)
|
161
224
|
|
162
|
-
expect
|
163
|
-
described_class::PresetNotFoundError,
|
164
|
-
'Preset unknown is not defined.'
|
165
|
-
)
|
225
|
+
expect(helper.ckeditor5_editor(editable_height: 600)).to include('editable-height="600px"')
|
166
226
|
end
|
167
227
|
end
|
168
228
|
end
|