ckeditor5 1.19.4 → 1.20.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,46 @@
2
2
 
3
3
  module CKEditor5::Rails::Hooks
4
4
  module SimpleForm
5
+ # Custom input type for Simple Form integration with CKEditor 5.
6
+ # This class enables seamless integration with Simple Form, allowing use of CKEditor 5
7
+ # as a form input with all its features and configurations.
8
+ #
9
+ # @example Basic usage in a form
10
+ # <%= simple_form_for @post do |f| %>
11
+ # <%= f.input :content,
12
+ # as: :ckeditor5,
13
+ # input_html: { style: 'width: 600px' },
14
+ # required: true
15
+ # %>
16
+ # <% end %>
17
+ #
18
+ # @example With custom preset and styling
19
+ # <%= simple_form_for @post do |f| %>
20
+ # <%= f.input :content,
21
+ # as: :ckeditor5,
22
+ # preset: :custom,
23
+ # type: :inline,
24
+ # input_html: {
25
+ # style: 'width: 600px',
26
+ # class: 'custom-editor',
27
+ # initial_data: 'Hello!'
28
+ # }
29
+ # %>
30
+ # <% end %>
31
+ #
32
+ # @example With validation and error handling
33
+ # <%= simple_form_for @post do |f| %>
34
+ # <%= f.input :content,
35
+ # as: :ckeditor5,
36
+ # required: true,
37
+ # input_html: { style: 'width: 600px' },
38
+ # error: 'Content cannot be blank'
39
+ # %>
40
+ # <% end %>
5
41
  class CKEditor5Input < ::SimpleForm::Inputs::Base
42
+ # Renders the CKEditor 5 input field
43
+ # @param wrapper_options [Hash] Options passed from the form wrapper
44
+ # @return [String] Rendered editor HTML
6
45
  def input(wrapper_options = nil)
7
46
  merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
8
47
  @builder.template.ckeditor5_editor(**editor_options(merged_input_options))
@@ -10,6 +49,9 @@ module CKEditor5::Rails::Hooks
10
49
 
11
50
  private
12
51
 
52
+ # Builds options hash for the editor
53
+ # @param merged_input_options [Hash] Combined input options
54
+ # @return [Hash] Options for CKEditor instance
13
55
  def editor_options(merged_input_options)
14
56
  {
15
57
  preset: input_options.fetch(:preset, :default),
@@ -5,6 +5,34 @@ require 'active_support'
5
5
  module CKEditor5::Rails
6
6
  module Presets
7
7
  module Concerns
8
+ # ConfigurationMethods provides functionality for configuring CKEditor 5 presets and instances.
9
+ #
10
+ # This module is included in preset builders and allows setting various configuration options
11
+ # for the editor.
12
+ #
13
+ # @example Basic configuration in preset
14
+ # presets.define :custom do
15
+ # configure :height, '400px'
16
+ # configure :width, '600px'
17
+ # end
18
+ #
19
+ # @example Complex configuration with nested options
20
+ # presets.define :custom do
21
+ # configure :image, {
22
+ # toolbar: ['imageTextAlternative', 'imageStyle:inline'],
23
+ # styles: ['alignLeft', 'alignCenter']
24
+ # }
25
+ # end
26
+ #
27
+ # @example Plugin-specific configuration
28
+ # presets.define :custom do
29
+ # configure :heading, {
30
+ # options: [
31
+ # { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
32
+ # { model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1' }
33
+ # ]
34
+ # }
35
+ # end
8
36
  module ConfigurationMethods
9
37
  extend ActiveSupport::Concern
10
38
 
@@ -12,6 +40,23 @@ module CKEditor5::Rails
12
40
  attr_reader :config
13
41
  end
14
42
 
43
+ # Sets a configuration value for a given key in the editor configuration.
44
+ #
45
+ # @param key [Symbol, String] The configuration key
46
+ # @param value [Object] The configuration value
47
+ #
48
+ # @example Setting simple configuration
49
+ # configure :width, '500px'
50
+ #
51
+ # @example Setting plugin configuration
52
+ # configure :toolbar, ['bold', 'italic', '|', 'undo', 'redo']
53
+ #
54
+ # @example Setting nested configuration
55
+ # configure :image, {
56
+ # styles: {
57
+ # options: ['alignLeft', 'alignCenter']
58
+ # }
59
+ # }
15
60
  def configure(key, value)
16
61
  config[key] = value
17
62
  end
@@ -6,6 +6,10 @@ module CKEditor5::Rails
6
6
  module PluginMethods
7
7
  private
8
8
 
9
+ # Register a plugin in the editor configuration
10
+ #
11
+ # @param plugin_obj [Editor::PropsBasePlugin] Plugin instance to register
12
+ # @return [Editor::PropsBasePlugin] The registered plugin
9
13
  def register_plugin(plugin_obj)
10
14
  config[:plugins] << plugin_obj
11
15
  plugin_obj
@@ -13,19 +17,69 @@ module CKEditor5::Rails
13
17
 
14
18
  public
15
19
 
20
+ # Registers an external plugin loaded from a URL
21
+ #
22
+ # @param name [Symbol] Plugin name
23
+ # @param kwargs [Hash] Plugin options like :script, :import_as, :window_name, :stylesheets
24
+ # @example Load plugin from URL
25
+ # external_plugin :MyPlugin, script: 'https://example.com/plugin.js'
26
+ # @example Load with import alias
27
+ # external_plugin :MyPlugin,
28
+ # script: 'https://example.com/plugin.js',
29
+ # import_as: 'Plugin'
16
30
  def external_plugin(name, **kwargs)
17
31
  register_plugin(Editor::PropsExternalPlugin.new(name, **kwargs))
18
32
  end
19
33
 
34
+ # Registers an inline plugin with raw JavaScript code
35
+ #
36
+ # @param name [Symbol] Plugin name
37
+ # @param code [String] JavaScript code defining the plugin
38
+ # @example Define custom highlight plugin
39
+ # inline_plugin :MyCustomPlugin, <<~JS
40
+ # import { Plugin } from 'ckeditor5';
41
+ #
42
+ # export default class MyCustomPlugin extends Plugin {
43
+ # static get pluginName() {
44
+ # return 'MyCustomPlugin';
45
+ # }
46
+ #
47
+ # init() {
48
+ # // Plugin initialization code
49
+ # }
50
+ # }
51
+ # JS
20
52
  def inline_plugin(name, code)
21
53
  register_plugin(Editor::PropsInlinePlugin.new(name, code))
22
54
  end
23
55
 
56
+ # Register a single plugin by name
57
+ #
58
+ # @param name [Symbol, Editor::PropsBasePlugin] Plugin name or instance
59
+ # @param kwargs [Hash] Plugin configuration options
60
+ # @example Register standard plugin
61
+ # plugin :Bold
62
+ # @example Register premium plugin
63
+ # plugin :RealTimeCollaboration, premium: true
64
+ # @example Register custom plugin
65
+ # plugin :MyPlugin, import_name: 'my-custom-plugin'
24
66
  def plugin(name, **kwargs)
25
67
  premium(true) if kwargs[:premium] && respond_to?(:premium)
26
68
  register_plugin(PluginsBuilder.create_plugin(name, **kwargs))
27
69
  end
28
70
 
71
+ # Register multiple plugins and configure plugin settings
72
+ #
73
+ # @param names [Array<Symbol>] Plugin names to register
74
+ # @param kwargs [Hash] Shared plugin configuration
75
+ # @example Register multiple plugins
76
+ # plugins :Bold, :Italic, :Underline
77
+ # @example Configure plugins with block
78
+ # plugins do
79
+ # remove :Heading
80
+ # append :SelectAll, :RemoveFormat
81
+ # prepend :SourceEditing
82
+ # end
29
83
  def plugins(*names, **kwargs, &block)
30
84
  config[:plugins] ||= []
31
85
 
@@ -8,11 +8,28 @@ module CKEditor5::Rails::Presets
8
8
  class Manager
9
9
  attr_reader :presets
10
10
 
11
+ # Initializes a new Manager instance and sets up the default preset
11
12
  def initialize
12
13
  @presets = {}
13
14
  define_default_preset
14
15
  end
15
16
 
17
+ # Define a new preset configuration
18
+ #
19
+ # @param name [Symbol] Name of the preset
20
+ # @param inherit [Boolean] Whether to inherit from default preset
21
+ # @example Define custom preset inheriting from default
22
+ # presets.define :custom do
23
+ # menubar visible: false
24
+ # toolbar :bold, :italic
25
+ # end
26
+ # @example Define preset from scratch
27
+ # presets.define :blank, inherit: false do
28
+ # version '43.3.1'
29
+ # gpl
30
+ # type :classic
31
+ # end
32
+ # @return [PresetBuilder] Created preset instance
16
33
  def define(name, inherit: true, &block)
17
34
  preset = if inherit && default.present?
18
35
  default.clone
@@ -24,35 +41,66 @@ module CKEditor5::Rails::Presets
24
41
  @presets[name] = preset
25
42
  end
26
43
 
44
+ # Override existing preset configuration
45
+ #
46
+ # @param name [Symbol] Name of the preset to override
47
+ # @example Override existing preset
48
+ # presets.override :custom do
49
+ # menubar visible: false
50
+ # toolbar do
51
+ # remove :underline, :heading
52
+ # end
53
+ # end
27
54
  def override(name, &block)
28
55
  @presets[name].instance_eval(&block)
29
56
  end
30
57
 
31
58
  alias extend override
32
59
 
60
+ # Get the default preset configuration
61
+ # @return [PresetBuilder, nil] Default preset or nil if not defined
33
62
  def default
34
63
  @presets[:default]
35
64
  end
36
65
 
66
+ # Get a preset by name
67
+ # @param name [Symbol] Name of the preset
68
+ # @return [PresetBuilder, nil] Found preset or nil if not found
37
69
  def [](name)
38
70
  @presets[name]
39
71
  end
40
72
 
41
73
  private
42
74
 
75
+ # Defines the default preset with common editor settings
76
+ # @example Basic configuration
77
+ # CKEditor5::Rails.configure do
78
+ # presets.define :default do
79
+ # version '43.3.1'
80
+ # gpl
81
+ # type :classic
82
+ # menubar
83
+ # end
84
+ # end
43
85
  def define_default_preset
44
86
  define :default do
87
+ # Set default version from gem constant
45
88
  version CKEditor5::Rails::DEFAULT_CKEDITOR_VERSION
46
89
 
90
+ # Enable automatic version upgrades for security patches
47
91
  automatic_upgrades
92
+
93
+ # Use GPL license and classic editor type
48
94
  gpl
49
95
  type :classic
50
96
  menubar
51
97
 
98
+ # Configure default toolbar items
52
99
  toolbar :undo, :redo, :|, :heading, :|, :bold, :italic, :underline, :|,
53
100
  :link, :insertImage, :mediaEmbed, :insertTable, :blockQuote, :|,
54
101
  :bulletedList, :numberedList, :todoList, :outdent, :indent
55
102
 
103
+ # Configure default plugins
56
104
  plugins :AccessibilityHelp, :Autoformat, :AutoImage, :Autosave,
57
105
  :BlockQuote, :Bold, :CloudServices,
58
106
  :Essentials, :Heading, :ImageBlock, :ImageCaption, :ImageInline,
@@ -64,6 +112,7 @@ module CKEditor5::Rails::Presets
64
112
  :TableColumnResize, :TableProperties, :TableToolbar,
65
113
  :TextTransformation, :TodoList, :Underline, :Undo, :Base64UploadAdapter
66
114
 
115
+ # Configure default image toolbar
67
116
  configure :image, {
68
117
  toolbar: ['imageTextAlternative', 'imageStyle:inline', 'imageStyle:block', 'imageStyle:side']
69
118
  }
@@ -8,6 +8,11 @@ module CKEditor5::Rails
8
8
  @items = plugins
9
9
  end
10
10
 
11
+ # Creates a plugin instance from a name or returns the plugin if it's already a PropsBasePlugin
12
+ #
13
+ # @param name [Symbol, Editor::PropsBasePlugin] Plugin name or instance
14
+ # @param kwargs [Hash] Additional plugin configuration
15
+ # @return [Editor::PropsBasePlugin] Plugin instance
11
16
  def self.create_plugin(name, **kwargs)
12
17
  if name.is_a?(Editor::PropsBasePlugin)
13
18
  name
@@ -16,10 +21,27 @@ module CKEditor5::Rails
16
21
  end
17
22
  end
18
23
 
24
+ # Removes specified plugins from the editor configuration
25
+ #
26
+ # @param names [Array<Symbol>] Names of plugins to remove
27
+ # @example Remove plugins from configuration
28
+ # plugins do
29
+ # remove :Heading, :Link
30
+ # end
19
31
  def remove(*names)
20
32
  names.each { |name| items.delete_if { |plugin| plugin.name == name } }
21
33
  end
22
34
 
35
+ # Prepends plugins to the beginning of the plugins list or before a specific plugin
36
+ #
37
+ # @param names [Array<Symbol>] Names of plugins to prepend
38
+ # @param before [Symbol, nil] Optional plugin name before which to insert new plugins
39
+ # @param kwargs [Hash] Additional plugin configuration
40
+ # @raise [ArgumentError] When the specified 'before' plugin is not found
41
+ # @example Prepend plugins to configuration
42
+ # plugins do
43
+ # prepend :Bold, :Italic, before: :Link
44
+ # end
23
45
  def prepend(*names, before: nil, **kwargs)
24
46
  new_plugins = names.map { |name| self.class.create_plugin(name, **kwargs) }
25
47
 
@@ -33,6 +55,16 @@ module CKEditor5::Rails
33
55
  end
34
56
  end
35
57
 
58
+ # Appends plugins to the end of the plugins list or after a specific plugin
59
+ #
60
+ # @param names [Array<Symbol>] Names of plugins to append
61
+ # @param after [Symbol, nil] Optional plugin name after which to insert new plugins
62
+ # @param kwargs [Hash] Additional plugin configuration
63
+ # @raise [ArgumentError] When the specified 'after' plugin is not found
64
+ # @example Append plugins to configuration
65
+ # plugins do
66
+ # append :Bold, :Italic, after: :Link
67
+ # end
36
68
  def append(*names, after: nil, **kwargs)
37
69
  new_plugins = names.map { |name| self.class.create_plugin(name, **kwargs) }
38
70
 
@@ -10,6 +10,12 @@ module CKEditor5::Rails
10
10
  include Concerns::ConfigurationMethods
11
11
  include Concerns::PluginMethods
12
12
 
13
+ # @example Basic initialization
14
+ # PresetBuilder.new do
15
+ # version '43.3.1'
16
+ # gpl
17
+ # type :classic
18
+ # end
13
19
  def initialize(&block)
14
20
  @version = nil
15
21
  @premium = false
@@ -28,6 +34,9 @@ module CKEditor5::Rails
28
34
  instance_eval(&block) if block_given?
29
35
  end
30
36
 
37
+ # @example Copy preset and modify it
38
+ # original = PresetBuilder.new
39
+ # copied = original.initialize_copy(original)
31
40
  def initialize_copy(source)
32
41
  super
33
42
 
@@ -41,10 +50,14 @@ module CKEditor5::Rails
41
50
  )
42
51
  end
43
52
 
53
+ # Check if preset is using premium features
54
+ # @return [Boolean]
44
55
  def premium?
45
56
  @premium
46
57
  end
47
58
 
59
+ # Check if preset is using GPL license
60
+ # @return [Boolean]
48
61
  def gpl?
49
62
  license_key == 'GPL'
50
63
  end
@@ -55,12 +68,24 @@ module CKEditor5::Rails
55
68
  end
56
69
  end
57
70
 
71
+ # Create a new preset by overriding current configuration
72
+ # @example Override existing preset
73
+ # preset.override do
74
+ # menubar visible: false
75
+ # toolbar do
76
+ # remove :underline, :heading
77
+ # end
78
+ # end
79
+ # @return [PresetBuilder] New preset instance
58
80
  def override(&block)
59
81
  clone.tap do |preset|
60
82
  preset.instance_eval(&block)
61
83
  end
62
84
  end
63
85
 
86
+ # Merge preset with configuration hash
87
+ # @param overrides [Hash] Configuration options to merge
88
+ # @return [self]
64
89
  def merge_with_hash!(**overrides) # rubocop:disable Metrics/AbcSize
65
90
  @version = Semver.new(overrides[:version]) if overrides.key?(:version)
66
91
  @premium = overrides.fetch(:premium, premium)
@@ -76,12 +101,22 @@ module CKEditor5::Rails
76
101
  self
77
102
  end
78
103
 
104
+ # Set or get editable height in pixels
105
+ # @param height [Integer, nil] Height in pixels
106
+ # @example Set editor height to 300px
107
+ # editable_height 300
108
+ # @return [Integer, nil] Current height value
79
109
  def editable_height(height = nil)
80
110
  return @editable_height if height.nil?
81
111
 
82
112
  @editable_height = height
83
113
  end
84
114
 
115
+ # Configure CKBox integration
116
+ # @param version [String, nil] CKBox version
117
+ # @param theme [Symbol] Theme name (:lark)
118
+ # @example Enable CKBox with custom version
119
+ # ckbox '2.6.0', theme: :lark
85
120
  def ckbox(version = nil, theme: :lark)
86
121
  return @ckbox if version.nil?
87
122
 
@@ -91,6 +126,11 @@ module CKEditor5::Rails
91
126
  }
92
127
  end
93
128
 
129
+ # Set or get license key
130
+ # @param license_key [String, nil] License key
131
+ # @example Set commercial license
132
+ # license_key 'your-license-key'
133
+ # @return [String, nil] Current license key
94
134
  def license_key(license_key = nil)
95
135
  return @license_key if license_key.nil?
96
136
 
@@ -99,23 +139,41 @@ module CKEditor5::Rails
99
139
  cdn(:cloud) unless gpl?
100
140
  end
101
141
 
142
+ # Set GPL license and disable premium features
143
+ # @example Enable GPL license
144
+ # gpl
102
145
  def gpl
103
146
  license_key('GPL')
104
147
  premium(false)
105
148
  end
106
149
 
150
+ # Enable or check premium features
151
+ # @param premium [Boolean, nil] Enable/disable premium features
152
+ # @example Enable premium features
153
+ # premium true
154
+ # @return [Boolean] Premium status
107
155
  def premium(premium = nil)
108
156
  return @premium if premium.nil?
109
157
 
110
158
  @premium = premium
111
159
  end
112
160
 
161
+ # Set or get translations
162
+ # @param translations [Array<Symbol>] Language codes
163
+ # @example Add Polish and Spanish translations
164
+ # translations :pl, :es
165
+ # @return [Array<Symbol>] Current translations
113
166
  def translations(*translations)
114
167
  return @translations if translations.empty?
115
168
 
116
169
  @translations = translations
117
170
  end
118
171
 
172
+ # Set or get editor version
173
+ # @param version [String, nil] Editor version
174
+ # @example Set specific version
175
+ # version '43.3.1'
176
+ # @return [String, nil] Current version
119
177
  def version(version = nil)
120
178
  return @version&.to_s if version.nil?
121
179
 
@@ -127,14 +185,29 @@ module CKEditor5::Rails
127
185
  end
128
186
  end
129
187
 
188
+ # Enable or disable automatic version upgrades
189
+ # @param enabled [Boolean] Enable/disable upgrades
190
+ # @example Enable automatic upgrades
191
+ # automatic_upgrades enabled: true
130
192
  def automatic_upgrades(enabled: true)
131
193
  @automatic_upgrades = enabled
132
194
  end
133
195
 
196
+ # Check if automatic upgrades are enabled
197
+ # @return [Boolean]
134
198
  def automatic_upgrades?
135
199
  @automatic_upgrades
136
200
  end
137
201
 
202
+ # Configure CDN source
203
+ # @param cdn [Symbol, nil] CDN name or custom block
204
+ # @example Use jsDelivr CDN
205
+ # cdn :jsdelivr
206
+ # @example Custom CDN configuration
207
+ # cdn do |bundle, version, path|
208
+ # "https://custom-cdn.com/#{bundle}@#{version}/#{path}"
209
+ # end
210
+ # @return [Symbol, Proc] Current CDN configuration
138
211
  def cdn(cdn = nil, &block)
139
212
  return @cdn if cdn.nil? && block.nil?
140
213
 
@@ -150,6 +223,12 @@ module CKEditor5::Rails
150
223
  end
151
224
  end
152
225
 
226
+ # Set or get editor type
227
+ # @param type [Symbol, nil] Editor type (:classic, :inline, :balloon, :decoupled)
228
+ # @example Set editor type to inline
229
+ # type :inline
230
+ # @raise [ArgumentError] If invalid type provided
231
+ # @return [Symbol] Current editor type
153
232
  def type(type = nil)
154
233
  return @type if type.nil?
155
234
  raise ArgumentError, "Invalid editor type: #{type}" unless Editor::Props.valid_editor_type?(type)
@@ -157,16 +236,33 @@ module CKEditor5::Rails
157
236
  @type = type
158
237
  end
159
238
 
239
+ # Configure menubar visibility
240
+ # @param visible [Boolean] Show/hide menubar
241
+ # @example Hide menubar
242
+ # menubar visible: false
160
243
  def menubar(visible: true)
161
244
  config[:menuBar] = {
162
245
  isVisible: visible
163
246
  }
164
247
  end
165
248
 
249
+ # Check if menubar is visible
250
+ # @return [Boolean]
166
251
  def menubar?
167
252
  config.dig(:menuBar, :isVisible) || false
168
253
  end
169
254
 
255
+ # Configure toolbar items and grouping
256
+ # @param items [Array<Symbol>] Toolbar items
257
+ # @param should_group_when_full [Boolean] Enable grouping
258
+ # @example Configure toolbar items
259
+ # toolbar :bold, :italic, :|, :link
260
+ # @example Configure with block
261
+ # toolbar do
262
+ # append :selectAll
263
+ # remove :heading
264
+ # end
265
+ # @return [ToolbarBuilder] Toolbar configuration
170
266
  def toolbar(*items, should_group_when_full: true, &block)
171
267
  if @config[:toolbar].blank? || !items.empty?
172
268
  @config[:toolbar] = {
@@ -180,10 +276,20 @@ module CKEditor5::Rails
180
276
  builder
181
277
  end
182
278
 
279
+ # Check if language is configured
280
+ # @return [Boolean]
183
281
  def language?
184
282
  config[:language].present?
185
283
  end
186
284
 
285
+ # Configure editor language
286
+ # @param ui [Symbol, nil] UI language code
287
+ # @param content [Symbol] Content language code
288
+ # @example Set Polish UI and content language
289
+ # language :pl
290
+ # @example Different UI and content languages
291
+ # language :pl, content: :en
292
+ # @return [Hash, nil] Language configuration
187
293
  def language(ui = nil, content: ui) # rubocop:disable Naming/MethodParameterName
188
294
  return config[:language] if ui.nil?
189
295
 
@@ -195,6 +301,10 @@ module CKEditor5::Rails
195
301
  }
196
302
  end
197
303
 
304
+ # Configure simple upload adapter
305
+ # @param upload_url [String] Upload endpoint URL
306
+ # @example Enable upload adapter
307
+ # simple_upload_adapter '/uploads'
198
308
  def simple_upload_adapter(upload_url = '/uploads')
199
309
  plugins do
200
310
  remove(:Base64UploadAdapter)
@@ -204,6 +314,13 @@ module CKEditor5::Rails
204
314
  configure(:simpleUpload, { uploadUrl: upload_url })
205
315
  end
206
316
 
317
+ # Configure WProofreader plugin
318
+ # @param version [String, nil] Plugin version
319
+ # @param cdn [String, nil] CDN URL
320
+ # @param config [Hash] Plugin configuration
321
+ # @example Basic configuration
322
+ # wproofreader serviceId: 'your-service-ID',
323
+ # srcUrl: 'https://svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js'
207
324
  def wproofreader(version: nil, cdn: nil, **config)
208
325
  configure :wproofreader, config
209
326
  plugins do
@@ -8,10 +8,30 @@ module CKEditor5::Rails::Presets
8
8
  @items = items
9
9
  end
10
10
 
11
+ # Remove items from the editor toolbar.
12
+ #
13
+ # @param removed_items [Array<Symbol>] Toolbar items to be removed
14
+ # @example Remove items from toolbar
15
+ # toolbar do
16
+ # remove :underline, :heading
17
+ # end
11
18
  def remove(*removed_items)
12
19
  removed_items.each { |item| items.delete(item) }
13
20
  end
14
21
 
22
+ # Prepend items to the editor toolbar.
23
+ #
24
+ # @param prepended_items [Array<Symbol>] Toolbar items to be prepended
25
+ # @param before [Symbol, nil] Optional item before which to insert new items
26
+ # @example Prepend items to toolbar
27
+ # toolbar do
28
+ # prepend :selectAll, :|, :selectAll, :selectAll
29
+ # end
30
+ # @example Insert items before specific item
31
+ # toolbar do
32
+ # prepend :selectAll, before: :bold
33
+ # end
34
+ # @raise [ArgumentError] When the specified 'before' item is not found
15
35
  def prepend(*prepended_items, before: nil)
16
36
  if before
17
37
  index = items.index(before)
@@ -23,6 +43,19 @@ module CKEditor5::Rails::Presets
23
43
  end
24
44
  end
25
45
 
46
+ # Append items to the editor toolbar.
47
+ #
48
+ # @param appended_items [Array<Symbol>] Toolbar items to be appended
49
+ # @param after [Symbol, nil] Optional item after which to insert new items
50
+ # @example Append items to toolbar
51
+ # toolbar do
52
+ # append :selectAll, :|, :selectAll, :selectAll
53
+ # end
54
+ # @example Insert items after specific item
55
+ # toolbar do
56
+ # append :selectAll, after: :bold
57
+ # end
58
+ # @raise [ArgumentError] When the specified 'after' item is not found
26
59
  def append(*appended_items, after: nil)
27
60
  if after
28
61
  index = items.index(after)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CKEditor5
4
4
  module Rails
5
- VERSION = '1.19.4'
5
+ VERSION = '1.20.0'
6
6
 
7
7
  DEFAULT_CKEDITOR_VERSION = '43.3.1'
8
8
  end
@@ -153,7 +153,7 @@ RSpec.describe 'CKEditor5 Types Integration', type: :feature, js: true do
153
153
  container.appendChild(newEditable);
154
154
  JS
155
155
 
156
- sleep 0.1 # Wait for component initialization
156
+ sleep 1 # Wait for component initialization
157
157
 
158
158
  # Find and interact with new editable
159
159
  new_editable = find("[name='new-root']")