ckeditor5 1.19.5 → 1.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +5 -2
- data/README.md +2 -0
- data/lib/ckeditor5/rails/assets/assets_bundle_html_serializer.rb +43 -25
- data/lib/ckeditor5/rails/cdn/helpers.rb +81 -2
- data/lib/ckeditor5/rails/context/helpers.rb +28 -0
- data/lib/ckeditor5/rails/context/preset_builder.rb +33 -0
- data/lib/ckeditor5/rails/editor/helpers/config_helpers.rb +39 -0
- data/lib/ckeditor5/rails/editor/helpers/editor_helpers.rb +73 -13
- data/lib/ckeditor5/rails/engine.rb +11 -3
- data/lib/ckeditor5/rails/hooks/form.rb +44 -0
- data/lib/ckeditor5/rails/hooks/importmap.rb +58 -0
- data/lib/ckeditor5/rails/hooks/simple_form.rb +42 -0
- data/lib/ckeditor5/rails/presets/concerns/configuration_methods.rb +45 -0
- data/lib/ckeditor5/rails/presets/concerns/plugin_methods.rb +54 -0
- data/lib/ckeditor5/rails/presets/manager.rb +49 -0
- data/lib/ckeditor5/rails/presets/plugins_builder.rb +32 -0
- data/lib/ckeditor5/rails/presets/preset_builder.rb +117 -0
- data/lib/ckeditor5/rails/presets/toolbar_builder.rb +33 -0
- data/lib/ckeditor5/rails/version.rb +1 -1
- data/spec/e2e/features/editor_types_spec.rb +1 -1
- data/spec/e2e/spec_helper.rb +2 -7
- data/spec/lib/ckeditor5/rails/assets/{asset_bundle_hml_serializer_spec.rb → assets_bundle_hml_serializer_spec.rb} +58 -15
- data/spec/lib/ckeditor5/rails/cdn/helpers_spec.rb +41 -5
- data/spec/lib/ckeditor5/rails/engine_spec.rb +32 -0
- data/spec/lib/ckeditor5/rails/hooks/importmap_spec.rb +131 -0
- metadata +7 -4
data/spec/e2e/spec_helper.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'capybara'
|
4
4
|
require 'capybara/rspec'
|
5
5
|
require 'capybara/cuprite'
|
6
|
+
require 'rspec/retry'
|
6
7
|
|
7
8
|
ENV['RAILS_ENV'] ||= 'test'
|
8
9
|
|
@@ -40,16 +41,10 @@ Capybara.server = :webrick
|
|
40
41
|
Capybara.default_driver = :cuprite
|
41
42
|
Capybara.javascript_driver = :cuprite
|
42
43
|
|
43
|
-
require 'rspec/retry'
|
44
|
-
|
45
44
|
RSpec.configure do |config|
|
46
|
-
config.verbose_retry = true
|
47
|
-
|
48
45
|
config.around :each, :js do |example|
|
49
|
-
example.run_with_retry retry:
|
46
|
+
example.run_with_retry retry: 4, retry_wait: 5, default_sleep_interval: 2
|
50
47
|
end
|
51
|
-
|
52
|
-
config.profile_examples = 10
|
53
48
|
end
|
54
49
|
|
55
50
|
Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require f }
|
@@ -42,6 +42,13 @@ RSpec.describe CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer do
|
|
42
42
|
})
|
43
43
|
end
|
44
44
|
|
45
|
+
it 'should not include importmap if not requested' do
|
46
|
+
serializer = described_class.new(bundle, importmap: false)
|
47
|
+
html = serializer.to_html
|
48
|
+
|
49
|
+
expect(html).not_to have_tag('script', with: { type: 'importmap' })
|
50
|
+
end
|
51
|
+
|
45
52
|
it 'includes import map' do
|
46
53
|
expect(html).to have_tag('script', with: { type: 'importmap' }) do
|
47
54
|
with_text(%r{"@ckeditor/script2":"https://cdn\.com/script2\.js"})
|
@@ -131,13 +138,6 @@ RSpec.describe CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer do
|
|
131
138
|
nonce: 'true'
|
132
139
|
})
|
133
140
|
end
|
134
|
-
|
135
|
-
it 'memoizes scripts import map' do
|
136
|
-
first_call = serializer.send(:scripts_import_map_tag)
|
137
|
-
second_call = serializer.send(:scripts_import_map_tag)
|
138
|
-
|
139
|
-
expect(first_call.object_id).to eq(second_call.object_id)
|
140
|
-
end
|
141
141
|
end
|
142
142
|
|
143
143
|
describe '.url_resource_preload_type' do
|
@@ -153,17 +153,60 @@ RSpec.describe CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer do
|
|
153
153
|
expect(described_class.url_resource_preload_type('file.unknown')).to eq('fetch')
|
154
154
|
end
|
155
155
|
end
|
156
|
+
end
|
156
157
|
|
157
|
-
|
158
|
-
|
158
|
+
RSpec.describe CKEditor5::Rails::Assets::AssetsImportMap do
|
159
|
+
let(:scripts) do
|
160
|
+
[
|
161
|
+
CKEditor5::Rails::Assets::JSUrlImportMeta.new(
|
162
|
+
'https://cdn.com/script1.js',
|
163
|
+
window_name: 'WindowScript'
|
164
|
+
),
|
165
|
+
CKEditor5::Rails::Assets::JSUrlImportMeta.new(
|
166
|
+
'https://cdn.com/script2.js',
|
167
|
+
import_name: '@ckeditor/module'
|
168
|
+
),
|
169
|
+
CKEditor5::Rails::Assets::JSUrlImportMeta.new(
|
170
|
+
'https://cdn.com/script3.js',
|
171
|
+
import_name: 'https://example.com/module'
|
172
|
+
)
|
173
|
+
]
|
174
|
+
end
|
175
|
+
|
176
|
+
let(:bundle) { CKEditor5::Rails::Assets::AssetsBundle.new(scripts: scripts) }
|
177
|
+
subject(:import_map) { described_class.new(bundle) }
|
178
|
+
|
179
|
+
describe '#to_json' do
|
180
|
+
it 'includes only ESM scripts without URL-like imports' do
|
181
|
+
json = JSON.parse(import_map.to_json)
|
182
|
+
expect(json['imports']).to eq({
|
183
|
+
'@ckeditor/module' => 'https://cdn.com/script2.js'
|
184
|
+
})
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#to_html' do
|
189
|
+
it 'generates script tag with import map' do
|
190
|
+
html = import_map.to_html
|
191
|
+
expect(html).to have_tag('script', with: { type: 'importmap', nonce: 'true' }) do
|
192
|
+
with_text('{"imports":{"@ckeditor/module":"https://cdn.com/script2.js"}}')
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
159
196
|
|
197
|
+
describe '#looks_like_url? (private)' do
|
160
198
|
it 'returns false for invalid URIs' do
|
161
|
-
expect(
|
162
|
-
expect(
|
163
|
-
expect(
|
164
|
-
expect(
|
165
|
-
expect(
|
166
|
-
expect(
|
199
|
+
expect(import_map.send(:looks_like_url?, '@ckeditor/foo')).to be false
|
200
|
+
expect(import_map.send(:looks_like_url?, 'http')).to be false
|
201
|
+
expect(import_map.send(:looks_like_url?, 'invalid')).to be false
|
202
|
+
expect(import_map.send(:looks_like_url?, 'http://[invalid')).to be false
|
203
|
+
expect(import_map.send(:looks_like_url?, "http://example.com\nmalicious")).to be false
|
204
|
+
expect(import_map.send(:looks_like_url?, 'http://<invalid>')).to be false
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'returns true for valid HTTP(S) URLs' do
|
208
|
+
expect(import_map.send(:looks_like_url?, 'http://example.com')).to be true
|
209
|
+
expect(import_map.send(:looks_like_url?, 'https://cdn.com/script.js')).to be true
|
167
210
|
end
|
168
211
|
end
|
169
212
|
end
|
@@ -3,7 +3,16 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
RSpec.describe CKEditor5::Rails::Cdn::Helpers do
|
6
|
-
let(:test_class)
|
6
|
+
let(:test_class) do
|
7
|
+
Class.new do
|
8
|
+
include CKEditor5::Rails::Cdn::Helpers
|
9
|
+
|
10
|
+
def importmap_rendered?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
7
16
|
let(:helper) { test_class.new }
|
8
17
|
let(:preset) do
|
9
18
|
CKEditor5::Rails::Presets::PresetBuilder.new do
|
@@ -32,10 +41,6 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
|
|
32
41
|
|
33
42
|
describe '#ckeditor5_assets' do
|
34
43
|
context 'with valid preset' do
|
35
|
-
it 'returns serialized bundle html' do
|
36
|
-
expect(helper.ckeditor5_assets(preset: :default)).to eq(bundle_html)
|
37
|
-
end
|
38
|
-
|
39
44
|
it 'creates base bundle' do
|
40
45
|
expect(CKEditor5::Rails::Cdn::CKEditorBundle).to receive(:new)
|
41
46
|
.with(
|
@@ -218,6 +223,37 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
|
|
218
223
|
.to raise_error(ArgumentError, /forgot to define version/)
|
219
224
|
end
|
220
225
|
end
|
226
|
+
|
227
|
+
context 'when Rails.application.importmap is defined' do
|
228
|
+
before do
|
229
|
+
allow(helper).to receive(:importmap_available?).and_return(true)
|
230
|
+
allow(helper).to receive(:importmap_rendered?).and_return(false)
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'returns nil and stores html tags in context' do
|
234
|
+
result = helper.ckeditor5_assets(preset: :default)
|
235
|
+
expect(result).to be_nil
|
236
|
+
expect(context[:html_tags]).to eq(bundle_html)
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'raise exception if importmap_rendered?' do
|
240
|
+
allow(helper).to receive(:importmap_rendered?).and_return(true)
|
241
|
+
expect { helper.ckeditor5_assets(preset: :default) }
|
242
|
+
.to raise_error(CKEditor5::Rails::Cdn::Helpers::ImportmapAlreadyRenderedError)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context 'when importmap_available? is true returns html' do
|
247
|
+
before do
|
248
|
+
allow(helper).to receive(:importmap_available?).and_return(nil)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'returns html directly' do
|
252
|
+
result = helper.ckeditor5_assets(preset: :default)
|
253
|
+
expect(result).to eq(bundle_html)
|
254
|
+
expect(context[:html_tags]).to be_nil
|
255
|
+
end
|
256
|
+
end
|
221
257
|
end
|
222
258
|
|
223
259
|
describe 'cdn helper methods' do
|
@@ -102,5 +102,37 @@ RSpec.describe CKEditor5::Rails::Engine do
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
end
|
105
|
+
|
106
|
+
describe 'importmap initializer' do
|
107
|
+
context 'when Importmap is defined' do
|
108
|
+
module Importmap # rubocop:disable Lint/ConstantDefinitionInBlock
|
109
|
+
module ImportmapTagsHelper; end
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'prepends CKEditor5 importmap helper' do
|
113
|
+
initializer = described_class.initializers.find { |i| i.name == 'ckeditor5.importmap' }
|
114
|
+
initializer.run(Rails.application)
|
115
|
+
|
116
|
+
expect(Importmap::ImportmapTagsHelper.ancestors)
|
117
|
+
.to include(CKEditor5::Rails::Hooks::Importmap::ImportmapTagsHelper)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when Importmap is not defined' do
|
122
|
+
before do
|
123
|
+
@importmap = Importmap if defined?(Importmap)
|
124
|
+
Object.send(:remove_const, :Importmap) if defined?(Importmap)
|
125
|
+
end
|
126
|
+
|
127
|
+
after do
|
128
|
+
Object.const_set(:Importmap, @importmap) if @importmap
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'does not raise error' do
|
132
|
+
initializer = described_class.initializers.find { |i| i.name == 'ckeditor5.importmap' }
|
133
|
+
expect { initializer.run(Rails.application) }.not_to raise_error
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
105
137
|
end
|
106
138
|
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe CKEditor5::Rails::Hooks::Importmap::ImportmapTagsHelper do
|
6
|
+
let(:test_class) do
|
7
|
+
Class.new do
|
8
|
+
include ActionView::Helpers::TagHelper
|
9
|
+
include CKEditor5::Rails::Hooks::Importmap::ImportmapTagsHelper
|
10
|
+
|
11
|
+
def javascript_importmap_module_preload_tags(*)
|
12
|
+
'<script type="modulepreload">preload</script>'
|
13
|
+
end
|
14
|
+
|
15
|
+
def javascript_import_module_tag(*)
|
16
|
+
'<script type="module">import</script>'
|
17
|
+
end
|
18
|
+
|
19
|
+
def javascript_inline_importmap_tag(json)
|
20
|
+
"<script type=\"importmap\">#{json}</script>"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:helper) { test_class.new }
|
26
|
+
let(:importmap) { double('Importmap', to_json: '{"imports":{}}') }
|
27
|
+
|
28
|
+
before do
|
29
|
+
allow(Rails.application).to receive(:importmap).and_return(importmap)
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#javascript_importmap_tags' do
|
33
|
+
context 'without CKEditor context' do
|
34
|
+
it 'generates basic importmap tags' do
|
35
|
+
result = helper.javascript_importmap_tags
|
36
|
+
|
37
|
+
expect(result).to include('modulepreload')
|
38
|
+
expect(result).to include('module')
|
39
|
+
expect(helper).to be_importmap_rendered
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with CKEditor context' do
|
44
|
+
let(:bundle) do
|
45
|
+
CKEditor5::Rails::Assets::AssetsBundle.new(
|
46
|
+
scripts: [
|
47
|
+
CKEditor5::Rails::Assets::JSUrlImportMeta.new(
|
48
|
+
'https://cdn.com/script.js',
|
49
|
+
import_name: '@ckeditor/module'
|
50
|
+
)
|
51
|
+
]
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:html_tags) { '<script src="ckeditor.js"></script>' }
|
56
|
+
|
57
|
+
before do
|
58
|
+
helper.instance_variable_set(:@__ckeditor_context, {
|
59
|
+
bundle: bundle,
|
60
|
+
html_tags: html_tags
|
61
|
+
})
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'merges CKEditor importmap with base importmap' do
|
65
|
+
result = CGI.unescapeHTML(helper.javascript_importmap_tags)
|
66
|
+
|
67
|
+
expect(result).to include('@ckeditor/module')
|
68
|
+
expect(result).to include('https://cdn.com/script.js')
|
69
|
+
expect(result).to include(html_tags)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'handles invalid JSON gracefully' do
|
73
|
+
allow(importmap).to receive(:to_json).and_return('invalid json')
|
74
|
+
|
75
|
+
expect(Rails.logger).to receive(:error).with(/Failed to merge import maps/)
|
76
|
+
helper.javascript_importmap_tags
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'processes importmap in correct order when context is present' do
|
80
|
+
html = CGI.unescapeHTML(helper.javascript_importmap_tags)
|
81
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(html)
|
82
|
+
scripts = doc.css('script')
|
83
|
+
|
84
|
+
expect(scripts[0]['type']).to eq('importmap')
|
85
|
+
expect(scripts[1]['type']).to eq('modulepreload')
|
86
|
+
expect(scripts[2]['type']).to eq('module')
|
87
|
+
expect(scripts[3]['src']).to eq('ckeditor.js')
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'adds inline importmap when context is missing' do
|
91
|
+
helper.instance_variable_set(:@__ckeditor_context, nil)
|
92
|
+
html = CGI.unescapeHTML(helper.javascript_importmap_tags)
|
93
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(html)
|
94
|
+
scripts = doc.css('script')
|
95
|
+
|
96
|
+
expect(scripts[0]['type']).to eq('importmap')
|
97
|
+
expect(doc.css('script[src="ckeditor.js"]')).to be_empty
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#importmap_rendered?' do
|
103
|
+
it 'returns false by default' do
|
104
|
+
expect(helper).not_to be_importmap_rendered
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns true after rendering importmap' do
|
108
|
+
helper.javascript_importmap_tags
|
109
|
+
expect(helper).to be_importmap_rendered
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#merge_import_maps_json (private)' do
|
114
|
+
it 'correctly merges two valid import maps' do
|
115
|
+
map_a = '{"imports":{"a":"1"}}'
|
116
|
+
map_b = '{"imports":{"b":"2"}}'
|
117
|
+
|
118
|
+
result = JSON.parse(helper.send(:merge_import_maps_json, map_a, map_b))
|
119
|
+
expect(result['imports']).to eq('a' => '1', 'b' => '2')
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'returns second map when first is invalid' do
|
123
|
+
map_a = 'invalid json'
|
124
|
+
map_b = '{"imports":{"b":"2"}}'
|
125
|
+
|
126
|
+
expect(Rails.logger).to receive(:error).with(/Failed to merge import maps/)
|
127
|
+
result = helper.send(:merge_import_maps_json, map_a, map_b)
|
128
|
+
expect(result).to eq(map_b)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
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.
|
4
|
+
version: 1.20.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: 2024-
|
12
|
+
date: 2024-12-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- lib/ckeditor5/rails/engine.rb
|
71
71
|
- lib/ckeditor5/rails/helpers.rb
|
72
72
|
- lib/ckeditor5/rails/hooks/form.rb
|
73
|
+
- lib/ckeditor5/rails/hooks/importmap.rb
|
73
74
|
- lib/ckeditor5/rails/hooks/simple_form.rb
|
74
75
|
- lib/ckeditor5/rails/plugins/simple_upload_adapter.rb
|
75
76
|
- lib/ckeditor5/rails/plugins/wproofreader.rb
|
@@ -89,7 +90,7 @@ files:
|
|
89
90
|
- spec/e2e/spec_helper.rb
|
90
91
|
- spec/e2e/support/eventually.rb
|
91
92
|
- spec/e2e/support/form_helpers.rb
|
92
|
-
- spec/lib/ckeditor5/rails/assets/
|
93
|
+
- spec/lib/ckeditor5/rails/assets/assets_bundle_hml_serializer_spec.rb
|
93
94
|
- spec/lib/ckeditor5/rails/assets/assets_bundle_spec.rb
|
94
95
|
- spec/lib/ckeditor5/rails/cdn/ckbox_bundle_spec.rb
|
95
96
|
- spec/lib/ckeditor5/rails/cdn/ckeditor_bundle_spec.rb
|
@@ -108,6 +109,7 @@ files:
|
|
108
109
|
- spec/lib/ckeditor5/rails/editor/props_spec.rb
|
109
110
|
- spec/lib/ckeditor5/rails/engine_spec.rb
|
110
111
|
- spec/lib/ckeditor5/rails/hooks/form_spec.rb
|
112
|
+
- spec/lib/ckeditor5/rails/hooks/importmap_spec.rb
|
111
113
|
- spec/lib/ckeditor5/rails/hooks/simple_form_spec.rb
|
112
114
|
- spec/lib/ckeditor5/rails/plugins/wproofreader_spec.rb
|
113
115
|
- spec/lib/ckeditor5/rails/presets/manager_spec.rb
|
@@ -154,7 +156,7 @@ test_files:
|
|
154
156
|
- spec/e2e/spec_helper.rb
|
155
157
|
- spec/e2e/support/eventually.rb
|
156
158
|
- spec/e2e/support/form_helpers.rb
|
157
|
-
- spec/lib/ckeditor5/rails/assets/
|
159
|
+
- spec/lib/ckeditor5/rails/assets/assets_bundle_hml_serializer_spec.rb
|
158
160
|
- spec/lib/ckeditor5/rails/assets/assets_bundle_spec.rb
|
159
161
|
- spec/lib/ckeditor5/rails/cdn/ckbox_bundle_spec.rb
|
160
162
|
- spec/lib/ckeditor5/rails/cdn/ckeditor_bundle_spec.rb
|
@@ -173,6 +175,7 @@ test_files:
|
|
173
175
|
- spec/lib/ckeditor5/rails/editor/props_spec.rb
|
174
176
|
- spec/lib/ckeditor5/rails/engine_spec.rb
|
175
177
|
- spec/lib/ckeditor5/rails/hooks/form_spec.rb
|
178
|
+
- spec/lib/ckeditor5/rails/hooks/importmap_spec.rb
|
176
179
|
- spec/lib/ckeditor5/rails/hooks/simple_form_spec.rb
|
177
180
|
- spec/lib/ckeditor5/rails/plugins/wproofreader_spec.rb
|
178
181
|
- spec/lib/ckeditor5/rails/presets/manager_spec.rb
|