ckeditor5 1.7.0 → 1.9.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: 4325c958e2805d971859c841f0b2694490e35a7e4600e2b8bb60f35672493146
4
- data.tar.gz: 23aa528bcbfbec102647898aee0fb4c064e7d16bd051fc4bf45ae94b9ed16fb6
3
+ metadata.gz: bb520612d3f2847e8d70c48a8ffb3d1ad4be25800dd5f141a6948caf30b07978
4
+ data.tar.gz: 5f9850fb6a39774ab796f67b5dc95fa0ec1e6a5fe6f04fb3481f6ff17c76e026
5
5
  SHA512:
6
- metadata.gz: 7e12e3e13824889463c2500e5d26874c1dd7c1dac6c5dbf1d41b37e5bd66e25b642b92fdbcb943b4f99219302e9184bacc5c8b16902559511c69db2392e2d569
7
- data.tar.gz: '090b221f5bebaedac65be2db6a230409537b891bce481258106a575a58555b59fa2a0f55b125ea114115554ecba1b2d0f80845e3b1bea14f6f743af627972810'
6
+ metadata.gz: 7057a3e537f5626b4754b815c1f418ddac64301350aa3b0299d5051dcda474a5f397018389a0e7c773bc1d15687043498a2bcd44518581e4233f8ab4ae85dc52
7
+ data.tar.gz: 0526b5810f411971ce3adafa1bad252eabaffc566f3d637b6585c2a16a6d6c938078e8b88ed88b34e610477c87c66f5dfc74d092fab2f46f183327f2fca9d287
data/README.md CHANGED
@@ -84,6 +84,7 @@ Voilà! You have CKEditor 5 integrated with your Rails application. 🎉
84
84
  - [`plugin(name, premium:, import_name:)` method](#pluginname-premium-import_name-method)
85
85
  - [`plugins(*names, **kwargs)` method](#pluginsnames-kwargs-method)
86
86
  - [`inline_plugin(name, code)` method](#inline_pluginname-code-method)
87
+ - [`ckeditor5_element_ref(selector)` method](#ckeditor5_element_refselector-method)
87
88
  - [Including CKEditor 5 assets 📦](#including-ckeditor-5-assets-)
88
89
  - [Format 📝](#format-)
89
90
  - [Using default preset](#using-default-preset)
@@ -100,6 +101,9 @@ Voilà! You have CKEditor 5 integrated with your Rails application. 🎉
100
101
  - [Inline editor 📝](#inline-editor-)
101
102
  - [Balloon editor 🎈](#balloon-editor-)
102
103
  - [Decoupled editor 🌐](#decoupled-editor-)
104
+ - [Using Context 📦](#using-context-)
105
+ - [Benefits of Using Context in Collaboration 🤝](#benefits-of-using-context-in-collaboration-)
106
+ - [Using Context in CKEditor 5 🔄](#using-context-in-ckeditor-5-)
103
107
  - [How to access editor instance? 🤔](#how-to-access-editor-instance-)
104
108
  - [Common Tasks and Solutions 💡](#common-tasks-and-solutions-)
105
109
  - [Setting Editor Language 🌐](#setting-editor-language-)
@@ -183,9 +187,6 @@ Configuration of the editor can be complex, and it's recommended to use the [CKE
183
187
 
184
188
  ### Available Configuration Methods ⚙️
185
189
 
186
- <details>
187
- <summary>Expand to show available methods 📖</summary>
188
-
189
190
  #### `cdn(cdn = nil, &block)` method
190
191
 
191
192
  Defines the CDN to be used for CKEditor 5 assets. The example below shows how to set the CDN to `:jsdelivr`:
@@ -445,7 +446,9 @@ end
445
446
 
446
447
  #### `configure(name, value)` method
447
448
 
448
- Allows you to set custom configuration options. You can pass the name of the option and its value as arguments. The example below show how to set the default protocol for the link plugin to `https://`:
449
+ Allows you to set custom configuration options. You can pass the name of the option and its value as arguments. The [`ckeditor5_element_ref(selector)` helper](#ckeditor5_element_refselector-method) allows you to reference DOM elements that will be used by the editor's features. It's particularly useful for features that need to check element presence or operate on specific DOM elements.
450
+
451
+ For example, you can use it to configure font family dropdown to show only fonts available in specific elements:
449
452
 
450
453
  ```rb
451
454
  # config/initializers/ckeditor5.rb
@@ -453,8 +456,19 @@ Allows you to set custom configuration options. You can pass the name of the opt
453
456
  CKEditor5::Rails.configure do
454
457
  # ... other configuration
455
458
 
456
- configure :link, {
457
- defaultProtocol: 'https://'
459
+ configure :fontFamily, {
460
+ supportAllValues: true,
461
+ options: [
462
+ 'default',
463
+ 'Arial, Helvetica, sans-serif',
464
+ 'Courier New, Courier, monospace',
465
+ 'Georgia, serif',
466
+ 'Lucida Sans Unicode, Lucida Grande, sans-serif',
467
+ 'Tahoma, Geneva, sans-serif',
468
+ 'Times New Roman, Times, serif',
469
+ 'Trebuchet MS, Helvetica, sans-serif',
470
+ 'Verdana, Geneva, sans-serif'
471
+ ]
458
472
  }
459
473
  end
460
474
  ```
@@ -538,7 +552,22 @@ CKEditor5::Rails.configure do
538
552
  JS
539
553
  end
540
554
  ```
541
- </details>
555
+
556
+ #### `ckeditor5_element_ref(selector)` method
557
+
558
+ Defines a reference to a CKEditor 5 element. In other words, it allows you to reference DOM elements that will be used by the editor's features. It's particularly useful for features that need to check element presence or operate on specific DOM elements. The primary example is the `presence list` feature that requires a reference to the element that will be used to display the list.
559
+
560
+ ```rb
561
+ # config/initializers/ckeditor5.rb
562
+
563
+ CKEditor5::Rails.configure do
564
+ # ... other configuration
565
+
566
+ configure :yourPlugin, {
567
+ element: ckeditor5_element_ref("body")
568
+ }
569
+ end
570
+ ```
542
571
 
543
572
  ## Including CKEditor 5 assets 📦
544
573
 
@@ -934,6 +963,46 @@ If you want to use a decoupled editor, you can pass the `type` keyword argument
934
963
  <% end %>
935
964
  ```
936
965
 
966
+ ## Using Context 📦
967
+
968
+ Context CKEditor 5 is a feature that allows multiple editor instances to share a common configuration and state. This is particularly useful in collaborative environments where multiple users are editing different parts of the same document simultaneously. By using a shared context, all editor instances can synchronize their configurations, plugins, and other settings, ensuring a consistent editing experience across all users.
969
+
970
+ ### Benefits of Using Context in Collaboration 🤝
971
+
972
+ 1. **Consistency**: Ensures that all editor instances have the same configuration, plugins, and settings, providing a uniform editing experience.
973
+ 2. **Synchronization**: Allows real-time synchronization of content and changes across multiple editor instances, making collaborative editing seamless.
974
+ 3. **Resource Sharing**: Reduces the overhead of loading and initializing multiple editor instances by sharing common resources and configurations.
975
+ 4. **Simplified Management**: Makes it easier to manage and update the configuration and state of multiple editor instances from a single point.
976
+
977
+ ### Using Context in CKEditor 5 🔄
978
+
979
+ Format of the `ckeditor5_context` helper:
980
+
981
+ ```erb
982
+ <%= ckeditor5_context config: { ...you context config... }, plugins: [ ...your context plugins... ] do %>
983
+ <%= ckeditor5_editor %>
984
+ <%= ckeditor5_editor %>
985
+ <% end %>
986
+ ```
987
+
988
+ Example usage:
989
+
990
+ ```erb
991
+ <!-- app/views/demos/index.html.erb -->
992
+
993
+ <% content_for :head do %>
994
+ <%= ckeditor5_assets preset: :ultrabasic %>
995
+ <% end %>
996
+
997
+ <%= ckeditor5_context do %>
998
+ <%= ckeditor5_editor initial_data: 'Hello World' %>
999
+
1000
+ <br>
1001
+
1002
+ <%= ckeditor5_editor initial_data: 'Hello World 2' %>
1003
+ <% end %>
1004
+ ```
1005
+
937
1006
  ## How to access editor instance? 🤔
938
1007
 
939
1008
  You can access the editor instance using plain HTML and JavaScript, as CKEditor 5 is a web component with defined `instance`, `instancePromise` and `editables` properties.
@@ -57,16 +57,30 @@ class CKEditorComponent extends HTMLElement {
57
57
  /** @type {String} Initial HTML passed to component */
58
58
  #initialHTML = '';
59
59
 
60
+ /** @type {CKEditorContextComponent|null} */
61
+ #context = null;
62
+
63
+ /** @type {String} ID of editor within context */
64
+ #contextEditorId = null;
65
+
60
66
  /**
61
67
  * Lifecycle callback when element is connected to DOM
62
68
  * Initializes the editor when DOM is ready
63
69
  * @protected
64
70
  */
65
71
  connectedCallback() {
72
+ this.#context = this.closest('ckeditor-context-component');
66
73
  this.#initialHTML = this.innerHTML;
67
74
 
68
75
  try {
69
- execIfDOMReady(() => this.#reinitializeEditor());
76
+ execIfDOMReady(async () => {
77
+ if (this.#context) {
78
+ await this.#context.instancePromise.promise;
79
+ this.#context.registerEditor(this);
80
+ }
81
+
82
+ await this.reinitializeEditor();
83
+ });
70
84
  } catch (error) {
71
85
  console.error('Failed to initialize editor:', error);
72
86
  this.dispatchEvent(new CustomEvent('editor-error', { detail: error }));
@@ -84,7 +98,7 @@ class CKEditorComponent extends HTMLElement {
84
98
  if (oldValue !== null &&
85
99
  oldValue !== newValue &&
86
100
  CKEditorComponent.observedAttributes.includes(name) && this.isConnected) {
87
- await this.#reinitializeEditor();
101
+ await this.reinitializeEditor();
88
102
  }
89
103
  }
90
104
 
@@ -94,9 +108,12 @@ class CKEditorComponent extends HTMLElement {
94
108
  * @protected
95
109
  */
96
110
  async disconnectedCallback() {
111
+ if (this.#context) {
112
+ this.#context.unregisterEditor(this);
113
+ }
114
+
97
115
  try {
98
- await this.instance?.destroy();
99
- await this.watchdog?.destroy();
116
+ await this.#destroy();
100
117
  } catch (error) {
101
118
  console.error('Failed to destroy editor:', error);
102
119
  }
@@ -119,6 +136,7 @@ class CKEditorComponent extends HTMLElement {
119
136
 
120
137
  /**
121
138
  * Determines appropriate editor element tag based on editor type
139
+ *
122
140
  * @private
123
141
  * @returns {string} HTML tag name to use
124
142
  */
@@ -132,6 +150,40 @@ class CKEditorComponent extends HTMLElement {
132
150
  }
133
151
  }
134
152
 
153
+ /**
154
+ * Gets the CKEditor context instance if available.
155
+ *
156
+ * @private
157
+ * @returns {import('ckeditor5').ContextWatchdog|null}
158
+ */
159
+ get #contextWatchdog() {
160
+ return this.#context?.instance;
161
+ }
162
+
163
+ /**
164
+ * Destroys the editor instance and watchdog if available
165
+ */
166
+ async #destroy() {
167
+ if (this.#contextEditorId) {
168
+ await this.#contextWatchdog.remove(this.#contextEditorId);
169
+ }
170
+
171
+ await this.instance?.destroy();
172
+ await this.watchdog?.destroy();
173
+ }
174
+
175
+ /**
176
+ * Gets editor configuration with resolved element references
177
+ *
178
+ * @private
179
+ * @returns {EditorConfig}
180
+ */
181
+ #getConfig() {
182
+ const config = JSON.parse(this.getAttribute('config') || '{}');
183
+
184
+ return resolveElementReferences(config);
185
+ }
186
+
135
187
  /**
136
188
  * Creates a new CKEditor instance
137
189
  *
@@ -166,13 +218,27 @@ class CKEditorComponent extends HTMLElement {
166
218
  plugins,
167
219
  };
168
220
 
169
- console.warn('Initializing CKEditor with:', { config, watchdog: this.hasWatchdog() });
221
+ console.warn('Initializing CKEditor with:', { config, watchdog: this.hasWatchdog(), context: this.#context });
170
222
 
171
223
  // Initialize watchdog if needed
172
224
  let watchdog = null;
173
225
  let instance = null;
174
-
175
- if (this.hasWatchdog()) {
226
+ let contextId = null;
227
+
228
+ if (this.#context) {
229
+ contextId = uid();
230
+
231
+ await this.#contextWatchdog.add( {
232
+ creator: (_element, _config) => Editor.create(_element, _config),
233
+ id: contextId,
234
+ sourceElementOrData: content,
235
+ type: 'editor',
236
+ config,
237
+ } );
238
+
239
+ instance = this.#contextWatchdog.getItem(contextId);
240
+ } else if (this.hasWatchdog()) {
241
+ // Let's create use with plain watchdog.
176
242
  const { EditorWatchdog } = await import('ckeditor5');
177
243
  const watchdog = new EditorWatchdog(Editor);
178
244
 
@@ -180,12 +246,14 @@ class CKEditorComponent extends HTMLElement {
180
246
 
181
247
  instance = watchdog.editor;
182
248
  } else {
249
+ // Let's create the editor without watchdog.
183
250
  instance = await Editor.create(content, config);
184
251
  }
185
252
 
186
253
  this.dispatchEvent(new CustomEvent('editor-ready', { detail: instance }));
187
254
 
188
255
  return {
256
+ contextId,
189
257
  instance,
190
258
  watchdog,
191
259
  };
@@ -197,11 +265,12 @@ class CKEditorComponent extends HTMLElement {
197
265
  * @private
198
266
  * @returns {Promise<void>}
199
267
  */
200
- async #reinitializeEditor() {
268
+ async reinitializeEditor() {
201
269
  if (this.instance) {
202
270
  this.instancePromise = Promise.withResolvers();
203
271
 
204
- await this.instance.destroy();
272
+ await this.#destroy();
273
+
205
274
  this.instance = null;
206
275
  }
207
276
 
@@ -222,10 +291,11 @@ class CKEditorComponent extends HTMLElement {
222
291
  }
223
292
 
224
293
  try {
225
- const { watchdog, instance } = await this.#initializeEditor(this.editables || this.#getConfig().initialData || '');
294
+ const { watchdog, instance, contextId } = await this.#initializeEditor(this.editables || this.#getConfig().initialData || '');
226
295
 
227
296
  this.watchdog = watchdog;
228
297
  this.instance = instance;
298
+ this.#contextEditorId = contextId;
229
299
 
230
300
  this.#setupContentSync();
231
301
  this.#setupEditableHeight();
@@ -273,16 +343,6 @@ class CKEditorComponent extends HTMLElement {
273
343
  return this.getAttribute('watchdog') === 'true';
274
344
  }
275
345
 
276
- /**
277
- * Parses editor configuration from config attribute
278
- *
279
- * @private
280
- * @returns {EditorConfig}
281
- */
282
- #getConfig() {
283
- return JSON.parse(this.getAttribute('config') || '{}');
284
- }
285
-
286
346
  /**
287
347
  * Queries and validates editable elements
288
348
  *
@@ -455,6 +515,129 @@ class CKEditorComponent extends HTMLElement {
455
515
  }
456
516
  }
457
517
 
518
+ /**
519
+ * Custom element that provides shared CKEditor context for multiple editors.
520
+ *
521
+ * @extends HTMLElement
522
+ * @example
523
+ *
524
+ * <ckeditor-context-component plugins='[ ... ]'>
525
+ * <ckeditor-component type="ClassicEditor" config='{"toolbar": ["bold", "italic"]}'>
526
+ * <ckeditor-component type="ClassicEditor" config='{"toolbar": ["bold", "italic"]}'>
527
+ * </ckeditor-component>
528
+ */
529
+ class CKEditorContextComponent extends HTMLElement {
530
+ static get observedAttributes() {
531
+ return ['plugins', 'config'];
532
+ }
533
+
534
+ /** @type {import('ckeditor5').Context|null} */
535
+ instance = null;
536
+
537
+ /** @type {Promise<import('ckeditor5').Context>} */
538
+ instancePromise = Promise.withResolvers();
539
+
540
+ /** @type {Set<CKEditorComponent>} */
541
+ #connectedEditors = new Set();
542
+
543
+ async connectedCallback() {
544
+ try {
545
+ execIfDOMReady(() => this.#initializeContext());
546
+ } catch (error) {
547
+ console.error('Failed to initialize context:', error);
548
+ this.dispatchEvent(new CustomEvent('context-error', { detail: error }));
549
+ }
550
+ }
551
+
552
+ async attributeChangedCallback(name, oldValue, newValue) {
553
+ if (oldValue !== null && oldValue !== newValue) {
554
+ await this.#initializeContext();
555
+ }
556
+ }
557
+
558
+ async disconnectedCallback() {
559
+ if (this.instance) {
560
+ await this.instance.destroy();
561
+ this.instance = null;
562
+ }
563
+ }
564
+
565
+ /**
566
+ * Register editor component with this context
567
+ *
568
+ * @param {CKEditorComponent} editor
569
+ */
570
+ registerEditor(editor) {
571
+ this.#connectedEditors.add(editor);
572
+ }
573
+
574
+ /**
575
+ * Unregister editor component from this context
576
+ *
577
+ * @param {CKEditorComponent} editor
578
+ */
579
+ unregisterEditor(editor) {
580
+ this.#connectedEditors.delete(editor);
581
+ }
582
+
583
+ /**
584
+ * Initialize CKEditor context with shared configuration
585
+ *
586
+ * @private
587
+ */
588
+ async #initializeContext() {
589
+ if (this.instance) {
590
+ this.instancePromise = Promise.withResolvers();
591
+
592
+ await this.instance.destroy();
593
+
594
+ this.instance = null;
595
+ }
596
+
597
+ const { Context, ContextWatchdog } = await import('ckeditor5');
598
+ const plugins = await this.#getPlugins();
599
+ const config = this.#getConfig();
600
+
601
+ this.instance = new ContextWatchdog(Context, {
602
+ crashNumberLimit: 10
603
+ });
604
+
605
+ await this.instance.create({
606
+ ...config,
607
+ plugins
608
+ });
609
+
610
+ this.instance.on('itemError', (...args) => {
611
+ console.error('Context item error:', ...args);
612
+ });
613
+
614
+ this.instancePromise.resolve(this.instance);
615
+ this.dispatchEvent(new CustomEvent('context-ready', { detail: this.instance }));
616
+
617
+ // Reinitialize connected editors.
618
+ await Promise.all(
619
+ [...this.#connectedEditors].map(editor => editor.reinitializeEditor())
620
+ );
621
+ }
622
+
623
+ async #getPlugins() {
624
+ const raw = this.getAttribute('plugins');
625
+
626
+ return loadAsyncImports(raw ? JSON.parse(raw) : []);
627
+ }
628
+
629
+ /**
630
+ * Gets context configuration with resolved element references.
631
+ *
632
+ * @private
633
+ */
634
+ #getConfig() {
635
+ const config = JSON.parse(this.getAttribute('config') || '{}');
636
+
637
+ return resolveElementReferences(config);
638
+ }
639
+ }
640
+
458
641
  /**
459
642
  * Tracks and manages editable roots for CKEditor MultiRoot editor.
460
643
  * Provides a proxy-based API for dynamically managing editable elements with automatic
@@ -824,6 +1007,83 @@ function loadAsyncImports(imports = []) {
824
1007
  }));
825
1008
  }
826
1009
 
1010
+
1011
+ /**
1012
+ * Checks if a key is safe to use in configuration objects to prevent prototype pollution.
1013
+ *
1014
+ * @param {string} key - Key name to check
1015
+ * @returns {boolean} True if key is safe to use.
1016
+ */
1017
+ function isSafeKey(key) {
1018
+ return typeof key === 'string' &&
1019
+ key !== '__proto__' &&
1020
+ key !== 'constructor' &&
1021
+ key !== 'prototype';
1022
+ }
1023
+
1024
+ /**
1025
+ * Resolves element references in configuration object.
1026
+ * Looks for objects with { $element: "selector" } format and replaces them with actual elements.
1027
+ *
1028
+ * @param {Object} obj - Configuration object to process
1029
+ * @returns {Object} Processed configuration object with resolved element references
1030
+ */
1031
+ function resolveElementReferences(obj) {
1032
+ if (!obj || typeof obj !== 'object') {
1033
+ return obj;
1034
+ }
1035
+
1036
+ if (Array.isArray(obj)) {
1037
+ return obj.map(item => resolveElementReferences(item));
1038
+ }
1039
+
1040
+ const result = Object.create(null);
1041
+
1042
+ for (const key of Object.getOwnPropertyNames(obj)) {
1043
+ if (!isSafeKey(key)) {
1044
+ console.warn(`Suspicious key "${key}" detected in config, skipping`);
1045
+ continue;
1046
+ }
1047
+
1048
+ const value = obj[key];
1049
+
1050
+ if (value && typeof value === 'object') {
1051
+ if (value.$element) {
1052
+ const selector = value.$element;
1053
+
1054
+ if (typeof selector !== 'string') {
1055
+ console.warn(`Invalid selector type for "${key}", expected string`);
1056
+ continue;
1057
+ }
1058
+
1059
+ const element = document.querySelector(selector);
1060
+
1061
+ if (!element) {
1062
+ console.warn(`Element not found for selector: ${selector}`);
1063
+ }
1064
+
1065
+ result[key] = element || null;
1066
+ } else {
1067
+ result[key] = resolveElementReferences(value);
1068
+ }
1069
+ } else {
1070
+ result[key] = value;
1071
+ }
1072
+ }
1073
+
1074
+ return result;
1075
+ }
1076
+
1077
+ /**
1078
+ * Custom element that provides shared CKEditor context for multiple editors.
1079
+ *
1080
+ * @returns {String} unique id
1081
+ */
1082
+ function uid() {
1083
+ return Math.random().toString(36).substring(2);
1084
+ }
1085
+
827
1086
  customElements.define('ckeditor-component', CKEditorComponent);
828
1087
  customElements.define('ckeditor-editable-component', CKEditorEditableComponent);
829
1088
  customElements.define('ckeditor-ui-part-component', CKEditorUIPartComponent);
1089
+ customElements.define('ckeditor-context-component', CKEditorContextComponent);
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'props'
4
+
5
+ module CKEditor5::Rails::Context
6
+ module Helpers
7
+ def ckeditor5_context(**config, &block)
8
+ context_props = Props.new(config)
9
+
10
+ tag.send(:'ckeditor-context-component', **context_props.to_attributes, &block)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5::Rails
4
+ module Context
5
+ class Props
6
+ def initialize(config)
7
+ @config = config
8
+ end
9
+
10
+ def to_attributes
11
+ {
12
+ plugins: serialize_plugins,
13
+ config: serialize_config
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :config
20
+
21
+ def serialize_plugins
22
+ (config[:plugins] || []).map { |plugin| Editor::PropsPlugin.normalize(plugin).to_h }.to_json
23
+ end
24
+
25
+ def serialize_config
26
+ config.except(:plugins).to_json
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5::Rails
4
+ module Editor::ConfigHelpers
5
+ def ckeditor5_element_ref(selector)
6
+ { '$element': selector }
7
+ end
8
+ end
9
+ end
@@ -3,9 +3,12 @@
3
3
  require_relative 'props_plugin'
4
4
  require_relative 'props_inline_plugin'
5
5
  require_relative 'props'
6
+ require_relative 'config_helpers'
6
7
 
7
8
  module CKEditor5::Rails
8
9
  module Editor::Helpers
10
+ include Editor::ConfigHelpers
11
+
9
12
  class EditorContextError < StandardError; end
10
13
  class PresetNotFoundError < ArgumentError; end
11
14
  class InvalidEditableHeightError < ArgumentError; end
@@ -26,16 +29,13 @@ module CKEditor5::Rails
26
29
  type ||= preset.type
27
30
 
28
31
  validated_height = validate_editable_height(type, editable_height) || preset.editable_height
29
- editor_props = Editor::Props.new(
30
- controller_context, type, config,
31
- watchdog: watchdog
32
- )
33
-
34
- render_editor_component(
35
- editor_props,
36
- html_attributes.merge(validated_height ? { 'editable-height' => validated_height } : {}),
37
- &block
38
- )
32
+ editor_props = Editor::Props.new(controller_context, type, config, watchdog: watchdog)
33
+
34
+ tag_attributes = html_attributes
35
+ .merge(editor_props.to_attributes)
36
+ .merge(validated_height ? { 'editable-height' => validated_height } : {})
37
+
38
+ tag.send(:'ckeditor-component', **tag_attributes, &block)
39
39
  end
40
40
 
41
41
  def ckeditor5_editable(name = nil, **kwargs, &block)
@@ -88,10 +88,6 @@ module CKEditor5::Rails
88
88
  raise PresetNotFoundError, "Preset #{preset} is not defined."
89
89
  end
90
90
 
91
- def render_editor_component(props, html_attributes, &block)
92
- tag.send(:'ckeditor-component', **props.to_attributes, **html_attributes, &block)
93
- end
94
-
95
91
  def validate_editable_height(type, height)
96
92
  return nil if height.nil?
97
93
 
@@ -3,11 +3,13 @@
3
3
  require_relative 'cdn/helpers'
4
4
  require_relative 'cloud/helpers'
5
5
  require_relative 'editor/helpers'
6
+ require_relative 'context/helpers'
6
7
 
7
8
  module CKEditor5::Rails
8
9
  module Helpers
9
10
  include Cdn::Helpers
10
11
  include Cloud::Helpers
11
12
  include Editor::Helpers
13
+ include Context::Helpers
12
14
  end
13
15
  end
@@ -3,6 +3,8 @@
3
3
  module CKEditor5::Rails
4
4
  module Presets
5
5
  class PresetBuilder
6
+ include Editor::ConfigHelpers
7
+
6
8
  attr_reader :config
7
9
 
8
10
  def initialize
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CKEditor5
4
4
  module Rails
5
- VERSION = '1.7.0'
5
+ VERSION = '1.9.0'
6
6
  end
7
7
  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.7.0
4
+ version: 1.9.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-11-12 00:00:00.000000000 Z
12
+ date: 2024-11-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -51,6 +51,9 @@ files:
51
51
  - lib/ckeditor5/rails/cdn/helpers.rb
52
52
  - lib/ckeditor5/rails/cdn/url_generator.rb
53
53
  - lib/ckeditor5/rails/cloud/helpers.rb
54
+ - lib/ckeditor5/rails/context/helpers.rb
55
+ - lib/ckeditor5/rails/context/props.rb
56
+ - lib/ckeditor5/rails/editor/config_helpers.rb
54
57
  - lib/ckeditor5/rails/editor/helpers.rb
55
58
  - lib/ckeditor5/rails/editor/props.rb
56
59
  - lib/ckeditor5/rails/editor/props_inline_plugin.rb