ckeditor5 1.16.2 → 1.17.1

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: 80773f82ac9fcdf35feac2e568206c4dd5dbd04240ae891b880549fc7192ef12
4
- data.tar.gz: d4c4244344977827288691f7846bce8737c70d9df170aff1fa2fb52a3a400d1a
3
+ metadata.gz: 78094e2b7cf2ec9677a1eb9ee629918df4b6e9de62104cd6e2c8713b02ae7776
4
+ data.tar.gz: 63816a1caf2f2c42f08321f0169fb14e54e2f6424bc80834890dfde68a76f22f
5
5
  SHA512:
6
- metadata.gz: 2b681fd82436a62b4da89064979c02f4952ba1c210473b3d00791fe34627555e6df6761c4fb9cdbd49ea3258a3ce508c7c2c013ae4dccb56eb452848f936024a
7
- data.tar.gz: 1c2170807abc784d8905b6817a8b1fb03c08d1f8ce3be48403923b96c255232c7acea65bacd417922e0014e5b18f7eb58dd6702837d0fc7bca3df936bee9774d
6
+ metadata.gz: b3691b024f1cedc6da4086fea1754f6f4d7acdc2d3d9a10f5628b0b54c539e941073cff74459dd776956c758fe4da1f78b54a6c8ab0128248e1ecc9b308ba168
7
+ data.tar.gz: a5d4109cc5f559144a66abd7ba1b672a27d1ad41131bdead590c144d4c4b2d1eb518953267bfee9fb6fa14c9cce027416de28dece065ed852c198fd4587e08dc
data/README.md CHANGED
@@ -44,8 +44,8 @@ In your view:
44
44
  <!-- app/views/demos/index.html.erb -->
45
45
 
46
46
  <% content_for :head do %>
47
- <!-- 📦 Loads CKEditor assets via importmap based on initializer config -->
48
- <%= ckeditor5_assets %>
47
+ <!-- 📦 Adds importmap with CKEditor 5 assets. Language is optional. -->
48
+ <%= ckeditor5_assets language: :en %>
49
49
  <% end %>
50
50
 
51
51
  <!-- 🖋️ CKEditor 5 might be placed using simple view helper ... -->
@@ -113,12 +113,12 @@ For extending CKEditor's functionality, refer to the [plugins directory](https:/
113
113
  - [`license_key(key)` method](#license_keykey-method)
114
114
  - [`premium` method](#premium-method)
115
115
  - [`editable_height(height)` method](#editable_heightheight-method)
116
+ - [`language(ui, content:)` method](#languageui-content-method)
116
117
  - [`translations(*languages)` method](#translationslanguages-method)
117
118
  - [`ckbox` method](#ckbox-method)
118
119
  - [`type(type)` method](#typetype-method)
119
120
  - [`toolbar(*items, should_group_when_full: true, &block)` method](#toolbaritems-should_group_when_full-true-block-method)
120
121
  - [`menubar(visible: true)` method](#menubarvisible-true-method)
121
- - [`language(ui, content:)` method](#languageui-content-method)
122
122
  - [`configure(name, value)` method](#configurename-value-method)
123
123
  - [`plugin(name, premium:, import_name:)` method](#pluginname-premium-import_name-method)
124
124
  - [`plugins(*names, **kwargs)` method](#pluginsnames-kwargs-method)
@@ -126,7 +126,7 @@ For extending CKEditor's functionality, refer to the [plugins directory](https:/
126
126
  - [`simple_upload_adapter(url)` method](#simple_upload_adapterurl-method)
127
127
  - [Controller / View helpers 📦](#controller--view-helpers-)
128
128
  - [`ckeditor5_element_ref(selector)` method](#ckeditor5_element_refselector-method)
129
- - [`ckeditor5_preset(&block)` method](#ckeditor5_presetblock-method)
129
+ - [`ckeditor5_preset(name = nil, &block)` method](#ckeditor5_presetname--nil-block-method)
130
130
  - [Including CKEditor 5 assets 📦](#including-ckeditor-5-assets-)
131
131
  - [Format 📝](#format-)
132
132
  - [Using default preset](#using-default-preset)
@@ -234,6 +234,8 @@ CKEditor5::Rails.configure do
234
234
  end
235
235
  ```
236
236
 
237
+ You can define presets in the controller using the `ckeditor5_preset` helper method. See it in the section below ([Controller / View helpers](#controller--view-helpers-)).
238
+
237
239
  Configuration of the editor can be complex, and it's recommended to use the [CKEditor 5 online builder](https://ckeditor.com/ckeditor-5/online-builder/) to generate the configuration. It allows you to select the features you want to include and generate the configuration code in JavaScript format. Keep in mind that you need to convert the JavaScript configuration to Ruby format before using it in this gem.
238
240
 
239
241
  ### Automatic upgrades 🔄
@@ -256,6 +258,11 @@ end
256
258
 
257
259
  #### `cdn(cdn = nil, &block)` method
258
260
 
261
+ <details>
262
+ <summary>Configure custom CDN URL pattern or use predefined CDNs like jsdelivr or unpkg</summary>
263
+
264
+ <br />
265
+
259
266
  Defines the CDN to be used for CKEditor 5 assets. The example below shows how to set the CDN to `:jsdelivr`:
260
267
 
261
268
  ```rb
@@ -283,9 +290,15 @@ CKEditor5::Rails.configure do
283
290
  end
284
291
  end
285
292
  ```
293
+ </details>
286
294
 
287
295
  #### `version(version)` method
288
296
 
297
+ <details>
298
+ <summary>Set up the version of CKEditor 5 to be used by the integration</summary>
299
+
300
+ <br />
301
+
289
302
  Defines the version of CKEditor 5 to be used. The example below shows how to set the version to `43.2.0`:
290
303
 
291
304
  ```rb
@@ -297,9 +310,15 @@ CKEditor5::Rails.configure do
297
310
  version '43.3.1'
298
311
  end
299
312
  ```
313
+ </details>
300
314
 
301
315
  #### `automatic_upgrades(enabled: true)` method
302
316
 
317
+ <details>
318
+ <summary>Enable or disable automatic security patches and bug fixes</summary>
319
+
320
+ <br />
321
+
303
322
  Defines if automatic upgrades should be enabled. It's enabled for the `:default` preset by default. The example below shows how to disable automatic upgrades:
304
323
 
305
324
  ```rb
@@ -315,9 +334,15 @@ end
315
334
  It means that the editor will automatically upgrade to the latest version when the gem is updated. It'll upgrade the editor only if the new patch or minor version is released. If you want to disable automatic upgrades, you can pass the `enabled: false` keyword argument to the `automatic_upgrades` method.
316
335
 
317
336
  Version is checked every nth day, where n is the number of days since the last check. Currently it's 4 days.
337
+ </details>
318
338
 
319
339
  #### `gpl` method
320
340
 
341
+ <details>
342
+ <summary>Defines the license of CKEditor 5. The example below shows how to set the license to GPL:</summary>
343
+
344
+ <br />
345
+
321
346
  Defines the license of CKEditor 5. The example below shows how to set the license to GPL:
322
347
 
323
348
  ```rb
@@ -329,9 +354,15 @@ CKEditor5::Rails.configure do
329
354
  gpl
330
355
  end
331
356
  ```
357
+ </details>
332
358
 
333
359
  #### `license_key(key)` method
334
360
 
361
+ <details>
362
+ <summary>Defines the license key of CKEditor 5. It calls `premium` method internally. The example below shows how to set the license key:</summary>
363
+
364
+ <br />
365
+
335
366
  Defines the license key of CKEditor 5. It calls `premium` method internally. The example below shows how to set the license key:
336
367
 
337
368
  ```rb
@@ -343,9 +374,15 @@ CKEditor5::Rails.configure do
343
374
  license_key 'your-license-key'
344
375
  end
345
376
  ```
377
+ </details>
346
378
 
347
379
  #### `premium` method
348
380
 
381
+ <details>
382
+ <summary>Defines if premium package should be included in JS assets. The example below shows how to add `ckeditor5-premium-features` to import maps:</summary>
383
+
384
+ <br />
385
+
349
386
  Defines if premium package should be included in JS assets. The example below shows how to add `ckeditor5-premium-features` to import maps:
350
387
 
351
388
  ```rb
@@ -357,9 +394,15 @@ CKEditor5::Rails.configure do
357
394
  premium
358
395
  end
359
396
  ```
397
+ </details>
360
398
 
361
399
  #### `editable_height(height)` method
362
400
 
401
+ <details>
402
+ <summary>Set editor height in pixels - useful for fixed-size layouts</summary>
403
+
404
+ <br />
405
+
363
406
  Defines the height of the editor. The example below shows how to set the height to `300px`:
364
407
 
365
408
  ```rb
@@ -371,9 +414,50 @@ CKEditor5::Rails.configure do
371
414
  editable_height 300
372
415
  end
373
416
  ```
417
+ </details>
418
+
419
+ #### `language(ui, content:)` method
420
+
421
+ <details>
422
+ <summary>Set UI and content language for the editor</summary>
423
+
424
+ <br />
425
+
426
+ Defines the language of the editor. You can pass the language code as an argument. Keep in mind that the UI and content language can be different. The example below shows how to set the Polish language for the UI and content:
427
+
428
+ ```rb
429
+ # config/initializers/ckeditor5.rb
430
+
431
+ CKEditor5::Rails.configure do
432
+ # ... other configuration
433
+
434
+ language :pl
435
+ end
436
+ ```
437
+
438
+ In order to set the language for the content, you can pass the `content` keyword argument:
439
+
440
+ ```rb
441
+ # config/initializers/ckeditor5.rb
442
+
443
+ CKEditor5::Rails.configure do
444
+ # ... other configuration
445
+
446
+ language :pl
447
+ end
448
+ ```
449
+
450
+ The example above sets the Polish language for the UI and content. If `pl` language was not defined in the translations, the builder will append the language to the list of translations to fetch. In order to prefetch more translations, use the helper below.
451
+
452
+ </details>
374
453
 
375
454
  #### `translations(*languages)` method
376
455
 
456
+ <details>
457
+ <summary>Load additional language files for the editor interface</summary>
458
+
459
+ <br />
460
+
377
461
  Defines the translations of CKEditor 5. You can pass the language codes as arguments. The example below shows how tell integration to fetch Polish and Spanish translations:
378
462
 
379
463
  ```rb
@@ -398,9 +482,15 @@ CKEditor5::Rails.configure do
398
482
  language :pl
399
483
  end
400
484
  ```
485
+ </details>
401
486
 
402
487
  #### `ckbox` method
403
488
 
489
+ <details>
490
+ <summary>Configure CKBox file manager integration</summary>
491
+
492
+ <br />
493
+
404
494
  Defines the CKBox plugin to be included in the editor. The example below shows how to include the CKBox plugin:
405
495
 
406
496
  ```rb
@@ -412,9 +502,15 @@ CKEditor5::Rails.configure do
412
502
  ckbox '2.6.0', theme: :lark
413
503
  end
414
504
  ```
505
+ </details>
415
506
 
416
507
  #### `type(type)` method
417
508
 
509
+ <details>
510
+ <summary>Select editor type (classic, inline, balloon, decoupled, multiroot)</summary>
511
+
512
+ <br />
513
+
418
514
  Defines the type of editor. Available options:
419
515
 
420
516
  - `:classic` - classic edytor
@@ -434,9 +530,15 @@ CKEditor5::Rails.configure do
434
530
  type :multiroot
435
531
  end
436
532
  ```
533
+ </details>
437
534
 
438
535
  #### `toolbar(*items, should_group_when_full: true, &block)` method
439
536
 
537
+ <details>
538
+ <summary>Define toolbar items and their grouping behavior</summary>
539
+
540
+ <br />
541
+
440
542
  Defines the toolbar items. You can use predefined items like `:undo`, `:redo`, `:|` or specify custom items. There are a few special items:
441
543
 
442
544
  - `:_` - breakpoint
@@ -486,9 +588,15 @@ CKEditor5::Rails.configure do
486
588
  end
487
589
  end
488
590
  ```
591
+ </details>
489
592
 
490
593
  #### `menubar(visible: true)` method
491
594
 
595
+ <details>
596
+ <summary>Set the visibility and options for the editor menubar</summary>
597
+
598
+ <br />
599
+
492
600
  Defines the visibility of the menubar. By default, it's set to `true`.
493
601
 
494
602
  ```rb
@@ -502,34 +610,14 @@ CKEditor5::Rails.configure do
502
610
  :bulletedList, :numberedList, :todoList, :outdent, :indent
503
611
  end
504
612
  ```
613
+ </details>
505
614
 
506
- #### `language(ui, content:)` method
507
-
508
- Defines the language of the editor. You can pass the language code as an argument. Keep in mind that the UI and content language can be different. The example below shows how to set the Polish language for the UI and content:
509
-
510
- ```rb
511
- # config/initializers/ckeditor5.rb
512
-
513
- CKEditor5::Rails.configure do
514
- # ... other configuration
515
-
516
- language :pl
517
- end
518
- ```
519
-
520
- In order to set the language for the content, you can pass the `content` keyword argument:
521
-
522
- ```rb
523
- # config/initializers/ckeditor5.rb
524
-
525
- CKEditor5::Rails.configure do
526
- # ... other configuration
615
+ #### `configure(name, value)` method
527
616
 
528
- language :en, content: :pl
529
- end
530
- ```
617
+ <details>
618
+ <summary>Add custom configuration options to the editor instance</summary>
531
619
 
532
- #### `configure(name, value)` method
620
+ <br />
533
621
 
534
622
  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.
535
623
 
@@ -557,9 +645,15 @@ CKEditor5::Rails.configure do
557
645
  }
558
646
  end
559
647
  ```
648
+ </details>
560
649
 
561
650
  #### `plugin(name, premium:, import_name:)` method
562
651
 
652
+ <details>
653
+ <summary>Register individual CKEditor plugins with optional premium flag</summary>
654
+
655
+ <br />
656
+
563
657
  Defines a plugin to be included in the editor. You can pass the name of the plugin as an argument. The `premium` keyword argument determines whether the plugin is premium. The `import_name` keyword argument specifies the name of the package to import the plugin from.
564
658
 
565
659
  The example below show how to import Bold plugin from the `ckeditor5` npm package:
@@ -597,11 +691,19 @@ CKEditor5::Rails.configure do
597
691
  plugin :YourPlugin, window_name: 'YourPlugin'
598
692
  end
599
693
  ```
694
+ </details>
600
695
 
601
696
  #### `plugins(*names, **kwargs)` method
602
697
 
698
+ <details>
699
+ <summary>Register multiple CKEditor plugins at once</summary>
700
+
701
+ <br />
702
+
603
703
  Defines the plugins to be included in the editor. You can specify multiple plugins by passing their names as arguments. The keyword arguments are identical to the configuration of the `plugin` method defined below.
604
704
 
705
+ <br />
706
+
605
707
  ```rb
606
708
  # config/initializers/ckeditor5.rb
607
709
 
@@ -625,9 +727,15 @@ CKEditor5::Rails.configure do
625
727
  end
626
728
  end
627
729
  ```
730
+ </details>
628
731
 
629
732
  #### `inline_plugin(name, code)` method
630
733
 
734
+ <details>
735
+ <summary>Define custom CKEditor plugins directly in the configuration</summary>
736
+
737
+ <br />
738
+
631
739
  ⚠️ **Warning:** Use with caution as this is an inline definition of the plugin code, and it can potentially cause XSS vulnerabilities. Only use this method with static, trusted JavaScript code. The example below shows how to define a custom plugin that highlights the text:
632
740
 
633
741
  ```rb
@@ -670,11 +778,19 @@ end
670
778
  ```
671
779
 
672
780
  This approach is resistant to XSS attacks as it avoids inline JavaScript.
781
+ </details>
673
782
 
674
783
  #### `simple_upload_adapter(url)` method
675
784
 
785
+ <details>
786
+ <summary>Configure server-side image upload endpoint</summary>
787
+
788
+ <br />
789
+
676
790
  Defines the URL for the simple upload adapter. The default endpoint is `/uploads` and the method is `POST`. The example below shows how to set the URL to `/uploads`:
677
791
 
792
+ <br />
793
+
678
794
  ```rb
679
795
  # config/initializers/ckeditor5.rb
680
796
 
@@ -685,12 +801,18 @@ CKEditor5::Rails.configure do
685
801
  # or: simple_upload_adapter '/uploads'
686
802
  end
687
803
  ```
804
+ </details>
688
805
 
689
806
  ### Controller / View helpers 📦
690
807
 
691
808
  #### `ckeditor5_element_ref(selector)` method
692
809
 
693
- 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.
810
+ <details>
811
+ <summary>Defines a reference to a CKEditor 5 element.</summary>
812
+
813
+ <br />
814
+
815
+ 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.
694
816
 
695
817
  ```rb
696
818
  # config/initializers/ckeditor5.rb
@@ -703,10 +825,16 @@ CKEditor5::Rails.configure do
703
825
  }
704
826
  end
705
827
  ```
828
+ </details>
829
+
830
+ #### `ckeditor5_preset(name = nil, &block)` method
831
+
832
+ <details>
833
+ <summary>The `ckeditor5_preset` method allows you to define a custom preset in your application controller.</summary>
706
834
 
707
- #### `ckeditor5_preset(&block)` method
835
+ <br />
708
836
 
709
- The `ckeditor5_preset` method allows you to define a custom preset in your application controller. It may be useful when you want to define a preset based on the current user or request.
837
+ It may be useful when you want to define a preset based on the current user or request.
710
838
 
711
839
  ```rb
712
840
  # app/controllers/application_controller.rb
@@ -741,6 +869,31 @@ In order to use the preset in the view, you can pass it to the `ckeditor5_assets
741
869
  <%= ckeditor5_editor %>
742
870
  ```
743
871
 
872
+ If you want to override the preset defined in the initializer, you can search for the preset by name and then override it (it'll create copy of the preset):
873
+
874
+ ```rb
875
+ # app/controllers/application_controller.rb
876
+
877
+ class ApplicationController < ActionController::Base
878
+ def show
879
+ @preset = ckeditor5_preset(:default).override do
880
+ version '43.3.1'
881
+
882
+ toolbar :sourceEditing, :|, :bold, :italic, :underline, :strikethrough,
883
+ :subscript, :superscript, :removeFormat, :|, :bulletedList, :numberedList,
884
+ :fontFamily, :fontSize, :|, :link, :anchor, :|,
885
+ :fontColor, :fontBackgroundColor
886
+
887
+ plugins :Essentials, :Paragraph, :Bold, :Italic, :Underline, :Strikethrough,
888
+ :Subscript, :Superscript, :RemoveFormat, :List, :Link, :Font,
889
+ :FontFamily, :FontSize, :FontColor, :FontBackgroundColor, :SourceEditing, :Essentials, :Paragraph
890
+ end
891
+ end
892
+ end
893
+ ```
894
+
895
+ </details>
896
+
744
897
  ## Including CKEditor 5 assets 📦
745
898
 
746
899
  To include CKEditor 5 assets in your application, you can use the `ckeditor5_assets` helper method. This method takes the version of CKEditor 5 as an argument and includes the necessary resources of the editor. Depending on the specified configuration, it includes the JS and CSS assets from the official CKEditor 5 CDN or one of the popular CDNs.
@@ -1018,7 +1171,8 @@ If you want to override the configuration of the editor specified in default or
1018
1171
  <!-- app/views/demos/index.html.erb -->
1019
1172
 
1020
1173
  <% content_for :head do %>
1021
- <%= ckeditor5_assets %>
1174
+ <!-- You can override default preset in assets helper too. -->
1175
+ <%= ckeditor5_assets translations: [:pl] %>
1022
1176
  <% end %>
1023
1177
 
1024
1178
  <%= ckeditor5_editor extra_config: { toolbar: [:Bold, :Italic] }, style: 'width: 600px' %>
@@ -1253,15 +1407,37 @@ This section covers frequent questions and scenarios when working with CKEditor
1253
1407
 
1254
1408
  ### Setting Editor Language 🌐
1255
1409
 
1256
- You can set the language of the editor using the `language` method in the `config/initializers/ckeditor5.rb` file. The `translations` method fetches the translations files, while the `language` method sets the default language of the editor.
1410
+ You can set the language of the editor using the `language` keyword argument. The example below shows how to set the language of the editor to Polish:
1411
+
1412
+ ```erb
1413
+ <!-- app/views/demos/index.html.erb -->
1414
+
1415
+ <% content_for :head do %>
1416
+ <%= ckeditor5_assets language: :pl %>
1417
+ <% end %>
1418
+
1419
+ <%= ckeditor5_editor %>
1420
+ ```
1421
+
1422
+ It can be also set in the initializer:
1257
1423
 
1258
1424
  ```rb
1259
- config.presets.override :default do
1260
- translations :pl, :es
1425
+ # config/initializers/ckeditor5.rb
1426
+
1427
+ CKEditor5::Rails.configure do
1428
+ # Optional, it load multiple translation packs: translations :pl, :es
1261
1429
  language :pl
1262
1430
  end
1263
1431
  ```
1264
1432
 
1433
+ ... or on the editor level (keep in mind to load translations in the assets helper):
1434
+
1435
+ ```erb
1436
+ <!-- app/views/demos/index.html.erb -->
1437
+
1438
+ <%= ckeditor5_editor language: :pl %>
1439
+ ```
1440
+
1265
1441
  ### Integrating with Forms 📋
1266
1442
 
1267
1443
  You can integrate CKEditor 5 with Rails form builders like `form_for` or `simple_form`. The example below shows how to integrate CKEditor 5 with a Rails form using the `form_for` helper:
@@ -13,14 +13,14 @@ require_relative 'ckbox_bundle'
13
13
  module CKEditor5::Rails
14
14
  module Cdn::Helpers
15
15
  def ckeditor5_assets(preset: :default, **kwargs)
16
- merge_with_editor_preset(preset, **kwargs) => {
16
+ mapped_preset = merge_with_editor_preset(preset, **kwargs)
17
+ mapped_preset => {
17
18
  cdn:,
18
19
  version:,
19
20
  translations:,
20
21
  ckbox:,
21
22
  license_key:,
22
- premium:,
23
- **kwargs
23
+ premium:
24
24
  }
25
25
 
26
26
  bundle = build_base_cdn_bundle(cdn, version, translations)
@@ -30,7 +30,7 @@ module CKEditor5::Rails
30
30
  @__ckeditor_context = {
31
31
  license_key: license_key,
32
32
  bundle: bundle,
33
- preset: preset
33
+ preset: mapped_preset
34
34
  }
35
35
 
36
36
  Assets::AssetsBundleHtmlSerializer.new(bundle).to_html
@@ -53,17 +53,17 @@ module CKEditor5::Rails
53
53
  'Please define it in initializer. Thank you!'
54
54
  end
55
55
 
56
- hash = found_preset.to_h_with_overrides(**kwargs)
56
+ new_preset = found_preset.clone.merge_with_hash!(**kwargs)
57
57
 
58
58
  %i[version type].each do |key|
59
- next if hash[key].present?
59
+ next if new_preset.public_send(key).present?
60
60
 
61
61
  raise ArgumentError,
62
62
  "Poor thing. You forgot to define #{key}. Make sure you passed `#{key}:` parameter to " \
63
63
  "`ckeditor5_assets` or defined default one in your `#{preset}` preset!"
64
64
  end
65
65
 
66
- hash
66
+ new_preset
67
67
  end
68
68
 
69
69
  def build_base_cdn_bundle(cdn, version, translations)
@@ -22,12 +22,13 @@ module CKEditor5::Rails
22
22
  # @param initial_data [String] Initial content for the editor
23
23
  # @param watchdog [Boolean] Whether to enable the CKEditor watchdog feature
24
24
  # @param editable_height [String, Integer] Height of the editable area (Classic editor only)
25
+ # @param language [String] Language code for the editor UI
25
26
  # @param html_attributes [Hash] Additional HTML attributes for the editor element
26
27
  def ckeditor5_editor( # rubocop:disable Metrics/ParameterLists
27
28
  preset: nil,
28
29
  config: nil, extra_config: {}, type: nil,
29
30
  initial_data: nil, watchdog: true,
30
- editable_height: nil,
31
+ editable_height: nil, language: nil,
31
32
  **html_attributes, &block
32
33
  )
33
34
  validate_editor_input!(initial_data, block)
@@ -41,7 +42,8 @@ module CKEditor5::Rails
41
42
  editor_props = Editor::Props.new(
42
43
  controller_context, type, config,
43
44
  watchdog: watchdog,
44
- editable_height: editable_height
45
+ editable_height: editable_height,
46
+ language: language
45
47
  )
46
48
 
47
49
  tag_attributes = html_attributes.merge(editor_props.to_attributes)
@@ -13,13 +13,17 @@ module CKEditor5::Rails::Editor
13
13
  multiroot: 'MultiRootEditor'
14
14
  }.freeze
15
15
 
16
- def initialize(controller_context, type, config, watchdog: true, editable_height: nil)
16
+ def initialize(
17
+ controller_context, type, config,
18
+ watchdog: true, editable_height: nil, language: nil
19
+ )
17
20
  raise ArgumentError, "Invalid editor type: #{type}" unless Props.valid_editor_type?(type)
18
21
 
19
22
  @controller_context = controller_context
20
23
  @watchdog = watchdog
21
24
  @type = type
22
25
  @config = config
26
+ @language = language
23
27
  @editable_height = EditableHeightNormalizer.new(type).normalize(editable_height)
24
28
  end
25
29
 
@@ -59,7 +63,10 @@ module CKEditor5::Rails::Editor
59
63
  def serialize_config
60
64
  config
61
65
  .except(:plugins)
62
- .tap { |cfg| cfg[:licenseKey] = controller_context[:license_key] if controller_context[:license_key] }
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
63
70
  .to_json
64
71
  end
65
72
  end
@@ -49,17 +49,33 @@ module CKEditor5::Rails
49
49
  license_key == 'GPL'
50
50
  end
51
51
 
52
- def to_h_with_overrides(**overrides)
53
- {
54
- version: overrides.fetch(:version, version),
55
- premium: overrides.fetch(:premium, premium),
56
- cdn: overrides.fetch(:cdn, cdn),
57
- translations: overrides.fetch(:translations, translations),
58
- license_key: overrides.fetch(:license_key, license_key),
59
- type: overrides.fetch(:type, type),
60
- ckbox: overrides.fetch(:ckbox, ckbox),
61
- config: config.merge(overrides.fetch(:config, {}))
62
- }
52
+ def deconstruct_keys(keys)
53
+ keys.index_with do |key|
54
+ public_send(key)
55
+ end
56
+ end
57
+
58
+ def override(&block)
59
+ clone.tap do |preset|
60
+ preset.instance_eval(&block)
61
+ end
62
+ end
63
+
64
+ def merge_with_hash!(language: nil, **overrides) # rubocop:disable Metrics/AbcSize
65
+ @version = Semver.new(overrides[:version]) if overrides.key?(:version)
66
+ @premium = overrides.fetch(:premium, premium)
67
+ @cdn = overrides.fetch(:cdn, cdn)
68
+ @translations = overrides.fetch(:translations, translations)
69
+ @license_key = overrides.fetch(:license_key, license_key)
70
+ @type = overrides.fetch(:type, type)
71
+ @editable_height = overrides.fetch(:editable_height, editable_height)
72
+ @automatic_upgrades = overrides.fetch(:automatic_upgrades, automatic_upgrades)
73
+ @ckbox = overrides.fetch(:ckbox, ckbox) if overrides.key?(:ckbox) || ckbox
74
+ @config = config.merge(overrides.fetch(:config, {}))
75
+
76
+ language(language) if language
77
+
78
+ self
63
79
  end
64
80
 
65
81
  def editable_height(height = nil)
@@ -169,6 +185,8 @@ module CKEditor5::Rails
169
185
  def language(ui = nil, content: ui) # rubocop:disable Naming/MethodParameterName
170
186
  return config[:language] if ui.nil?
171
187
 
188
+ @translations << ui.to_sym unless @translations.map(&:to_sym).include?(ui.to_sym)
189
+
172
190
  config[:language] = {
173
191
  ui: ui,
174
192
  content: content
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CKEditor5
4
4
  module Rails
5
- VERSION = '1.16.2'
5
+ VERSION = '1.17.1'
6
6
 
7
7
  DEFAULT_CKEDITOR_VERSION = '43.3.1'
8
8
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'e2e/spec_helper'
4
+
5
+ RSpec.describe 'Editor localization', type: :system do
6
+ describe 'setting locale via assets' do
7
+ it 'displays menubar in Polish' do
8
+ visit '/locale_via_assets'
9
+
10
+ expect(page).to have_css('.ck-editor__main')
11
+
12
+ within('.ck-menu-bar') do
13
+ expect(page).to have_content('Zmiana')
14
+ expect(page).to have_content('Wstaw')
15
+ expect(page).to have_content('Format')
16
+ end
17
+ end
18
+ end
19
+
20
+ describe 'setting locale via editor prop' do
21
+ it 'displays menubar in Spanish' do
22
+ visit '/locale_via_editor'
23
+
24
+ expect(page).to have_css('.ck-editor__main')
25
+
26
+ within('.ck-menu-bar') do
27
+ expect(page).to have_content('Editar')
28
+ expect(page).to have_content('Insertar')
29
+ expect(page).to have_content('Formato')
30
+ end
31
+ end
32
+ end
33
+
34
+ describe 'setting locale via preset' do
35
+ it 'displays menubar in Russian' do
36
+ visit '/locale_via_preset'
37
+
38
+ expect(page).to have_css('.ck-editor__main')
39
+
40
+ within('.ck-menu-bar') do
41
+ expect(page).to have_content('Редактировать')
42
+ expect(page).to have_content('Вставить')
43
+ expect(page).to have_content('Формат')
44
+ end
45
+ end
46
+ end
47
+ end
@@ -6,19 +6,16 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
6
6
  let(:test_class) { Class.new { include CKEditor5::Rails::Cdn::Helpers } }
7
7
  let(:helper) { test_class.new }
8
8
  let(:preset) do
9
- instance_double(
10
- CKEditor5::Rails::Presets::PresetBuilder,
11
- to_h_with_overrides: {
12
- cdn: :cloud,
13
- version: '34.1.0',
14
- type: 'classic',
15
- translations: %w[pl],
16
- ckbox: nil,
17
- license_key: nil,
18
- premium: false
19
- }
20
- )
9
+ CKEditor5::Rails::Presets::PresetBuilder.new do
10
+ version '34.1.0'
11
+ type :classic
12
+ translations :pl
13
+ cdn :cloud
14
+ license_key nil
15
+ premium false
16
+ end
21
17
  end
18
+
22
19
  let(:bundle_html) { '<script src="test.js"></script>' }
23
20
  let(:serializer) do
24
21
  instance_double(CKEditor5::Rails::Assets::AssetsBundleHtmlSerializer, to_html: bundle_html)
@@ -40,7 +37,7 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
40
37
  .with(
41
38
  instance_of(CKEditor5::Rails::Semver),
42
39
  'ckeditor5',
43
- translations: %w[pl],
40
+ translations: [:pl],
44
41
  cdn: :cloud
45
42
  )
46
43
  .and_call_original
@@ -50,18 +47,13 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
50
47
 
51
48
  context 'with premium features' do
52
49
  let(:preset) do
53
- instance_double(
54
- CKEditor5::Rails::Presets::PresetBuilder,
55
- to_h_with_overrides: {
56
- cdn: :cloud,
57
- version: '34.1.0',
58
- type: 'classic',
59
- translations: %w[pl],
60
- ckbox: nil,
61
- license_key: nil,
62
- premium: true
63
- }
64
- )
50
+ CKEditor5::Rails::Presets::PresetBuilder.new do
51
+ version '34.1.0'
52
+ type :classic
53
+ translations :pl
54
+ cdn :cloud
55
+ premium true
56
+ end
65
57
  end
66
58
 
67
59
  it 'creates base and premium bundles' do
@@ -69,7 +61,7 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
69
61
  .with(
70
62
  instance_of(CKEditor5::Rails::Semver),
71
63
  'ckeditor5',
72
- translations: %w[pl],
64
+ translations: [:pl],
73
65
  cdn: :cloud
74
66
  )
75
67
  .and_call_original
@@ -79,7 +71,7 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
79
71
  .with(
80
72
  instance_of(CKEditor5::Rails::Semver),
81
73
  'ckeditor5-premium-features',
82
- translations: %w[pl],
74
+ translations: [:pl],
83
75
  cdn: :cloud
84
76
  )
85
77
  .and_call_original
@@ -91,18 +83,13 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
91
83
 
92
84
  context 'with ckbox' do
93
85
  let(:preset) do
94
- instance_double(
95
- CKEditor5::Rails::Presets::PresetBuilder,
96
- to_h_with_overrides: {
97
- cdn: :cloud,
98
- version: '34.1.0',
99
- type: 'classic',
100
- translations: %w[pl],
101
- ckbox: { version: '1.0.0', theme: :lark },
102
- license_key: nil,
103
- premium: false
104
- }
105
- )
86
+ CKEditor5::Rails::Presets::PresetBuilder.new do
87
+ version '34.1.0'
88
+ type :classic
89
+ translations :pl
90
+ cdn :cloud
91
+ ckbox '1.0.0', theme: :lark
92
+ end
106
93
  end
107
94
 
108
95
  it 'creates ckbox bundle' do
@@ -117,49 +104,40 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
117
104
  helper.ckeditor5_assets(preset: :default)
118
105
  end
119
106
  end
107
+ end
120
108
 
121
- context 'when destructuring preset hash' do
122
- let(:preset) do
123
- instance_double(
124
- CKEditor5::Rails::Presets::PresetBuilder,
125
- to_h_with_overrides: {
126
- cdn: :cloud,
127
- version: '34.1.0',
128
- type: 'classic',
129
- translations: %w[pl],
130
- ckbox: nil,
131
- license_key: nil,
132
- premium: false,
133
- extra: 'value'
134
- }
135
- )
136
- end
137
-
138
- it 'successfully matches and extracts required parameters' do
139
- expect { helper.ckeditor5_assets(preset: :default) }.not_to raise_error
109
+ context 'when overriding preset values' do
110
+ let(:preset) do
111
+ CKEditor5::Rails::Presets::PresetBuilder.new do
112
+ version '34.1.0'
113
+ type :classic
114
+ translations :pl
115
+ cdn :cloud
116
+ license_key 'preset-license'
117
+ premium false
140
118
  end
141
119
  end
142
- end
143
120
 
144
- context 'with invalid preset' do
145
- before do
146
- allow(CKEditor5::Rails::Engine).to receive(:find_preset).and_return(nil)
121
+ it 'allows overriding preset values' do
122
+ helper.ckeditor5_assets(preset: :default, license_key: 'overridden-license')
123
+
124
+ expect(helper.instance_variable_get(:@__ckeditor_context)[:preset].license_key)
125
+ .to eq('overridden-license')
147
126
  end
148
127
 
149
- it 'raises error' do
150
- expect { helper.ckeditor5_assets(preset: :invalid) }
151
- .to raise_error(ArgumentError, /forgot to define your invalid preset/)
128
+ it 'preserves non-overridden preset values' do
129
+ helper.ckeditor5_assets(preset: :default, license_key: 'overridden-license')
130
+ preset_context = helper.instance_variable_get(:@__ckeditor_context)[:preset]
131
+
132
+ expect(preset_context.version).to eq('34.1.0')
133
+ expect(preset_context.premium?).to be false
134
+ expect(preset_context.cdn).to eq(:cloud)
135
+ expect(preset_context.translations).to eq([:pl])
136
+ expect(preset_context.type).to eq(:classic)
152
137
  end
153
138
  end
154
139
 
155
140
  context 'with missing required parameters' do
156
- let(:preset) do
157
- instance_double(
158
- CKEditor5::Rails::Presets::PresetBuilder,
159
- to_h_with_overrides: { cdn: :cloud }
160
- )
161
- end
162
-
163
141
  before do
164
142
  allow(helper).to receive(:merge_with_editor_preset).and_return({})
165
143
  end
@@ -170,54 +148,24 @@ RSpec.describe CKEditor5::Rails::Cdn::Helpers do
170
148
  end
171
149
  end
172
150
 
173
- context 'with empty hash from preset' do
174
- let(:preset) do
175
- instance_double(
176
- CKEditor5::Rails::Presets::PresetBuilder,
177
- to_h_with_overrides: {}
178
- )
179
- end
180
-
181
- it 'raises error about missing version and type' do
182
- expect { helper.ckeditor5_assets(preset: :default) }
183
- .to raise_error(ArgumentError, /forgot to define version/)
151
+ context 'destructure non-matching preset override' do
152
+ before do
153
+ allow(CKEditor5::Rails::Engine).to receive(:find_preset).and_return(nil)
184
154
  end
185
- end
186
- end
187
155
 
188
- context 'when overriding preset values with kwargs' do
189
- let(:preset) do
190
- CKEditor5::Rails::Presets::PresetBuilder.new do
191
- version '34.1.0'
192
- type :classic
193
- translations :pl
194
- cdn :cloud
195
- license_key 'preset-license'
196
- premium false
156
+ it 'raises error' do
157
+ expect { helper.ckeditor5_assets(preset: :invalid) }
158
+ .to raise_error(ArgumentError, /forgot to define your invalid preset/)
197
159
  end
198
160
  end
199
161
 
200
- before do
201
- allow(CKEditor5::Rails::Engine).to receive(:find_preset).and_return(preset)
202
- end
203
-
204
- it 'allows overriding preset values with kwargs' do
205
- result = helper.send(:merge_with_editor_preset, :default, license_key: 'overridden-license')
206
- expect(result).to include(license_key: 'overridden-license')
207
- end
162
+ context 'with empty preset' do
163
+ let(:preset) { CKEditor5::Rails::Presets::PresetBuilder.new }
208
164
 
209
- it 'preserves non-overridden preset values' do
210
- result = helper.send(:merge_with_editor_preset, :default, license_key: 'overridden-license')
211
- expect(result).to eq(
212
- version: '34.1.0',
213
- premium: false,
214
- cdn: :cloud,
215
- translations: [:pl],
216
- license_key: 'overridden-license',
217
- type: :classic,
218
- ckbox: nil,
219
- config: { plugins: [], toolbar: [] }
220
- )
165
+ it 'raises error about missing version and type' do
166
+ expect { helper.ckeditor5_assets(preset: :default) }
167
+ .to raise_error(ArgumentError, /forgot to define version/)
168
+ end
221
169
  end
222
170
  end
223
171
 
@@ -65,6 +65,19 @@ RSpec.describe CKEditor5::Rails::Editor::Helpers::Editor do
65
65
  end.to raise_error(ArgumentError, /Cannot pass initial data and block/)
66
66
  end
67
67
 
68
+ context 'when language is present' do
69
+ it 'passes language to editor props' do
70
+ result = helper.ckeditor5_editor(language: 'pl')
71
+
72
+ expect(result).to include('config=')
73
+ config_attr = result.match(/config="([^"]+)"/)[1]
74
+ decoded_config = CGI.unescape_html(config_attr)
75
+ parsed_config = JSON.parse(decoded_config)
76
+
77
+ expect(parsed_config['language']).to eq({ 'ui' => 'pl' })
78
+ end
79
+ end
80
+
68
81
  context 'when automatic upgrades are enabled' do
69
82
  before do
70
83
  allow(preset).to receive(:automatic_upgrades?).and_return(true)
@@ -45,6 +45,17 @@ RSpec.describe CKEditor5::Rails::Editor::Props do
45
45
  end
46
46
  end
47
47
 
48
+ context 'with language' do
49
+ subject(:props) { described_class.new(controller_context, type, config, language: 'pl') }
50
+
51
+ it 'includes language in config' do
52
+ config_json = props.to_attributes[:config]
53
+
54
+ expect(config_json).to include('language')
55
+ expect(JSON.parse(config_json)['language']).to eq({ 'ui' => 'pl' })
56
+ end
57
+ end
58
+
48
59
  context 'with license key' do
49
60
  let(:controller_context) do
50
61
  { bundle: double('Bundle', translations_scripts: []), license_key: 'ABC123' }
@@ -70,6 +70,22 @@ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
70
70
  end
71
71
  end
72
72
 
73
+ describe '#override' do
74
+ it 'returns a new instance with overridden values' do
75
+ builder.version '35.0.0'
76
+ builder.translations :en, :pl
77
+
78
+ overridden = builder.override do
79
+ version '36.0.0'
80
+ translations :de
81
+ end
82
+
83
+ expect(builder.version).to eq('35.0.0')
84
+ expect(overridden.version).to eq('36.0.0')
85
+ expect(overridden.translations).to eq([:de])
86
+ end
87
+ end
88
+
73
89
  describe 'configuration methods' do
74
90
  describe '#automatic_upgrades' do
75
91
  it 'enables automatic upgrades' do
@@ -266,35 +282,49 @@ RSpec.describe CKEditor5::Rails::Presets::PresetBuilder do
266
282
  end
267
283
  end
268
284
 
269
- describe '#to_h_with_overrides' do
270
- let(:builder) do
271
- described_class.new do
272
- version '35.0.0'
273
- premium true
274
- translations :en, :pl
275
- end
285
+ describe '#merge_with_hash!' do
286
+ it 'merges hash with current configuration' do
287
+ builder.merge_with_hash!(version: '32.0.0', type: :inline)
288
+ expect(builder.version).to eq('32.0.0')
289
+ expect(builder.type).to eq(:inline)
276
290
  end
277
291
 
278
- it 'returns hash with default values' do
279
- result = builder.to_h_with_overrides
280
- expect(result).to include(
281
- version: '35.0.0',
282
- premium: true,
283
- translations: %i[en pl]
284
- )
292
+ it 'returns self' do
293
+ expect(builder.merge_with_hash!(version: '35.0.0')).to eq(builder)
285
294
  end
286
295
 
287
- it 'applies overrides' do
288
- result = builder.to_h_with_overrides(
289
- version: '36.0.0',
290
- premium: false,
291
- translations: [:en]
292
- )
293
- expect(result).to include(
294
- version: '36.0.0',
295
- premium: false,
296
- translations: [:en]
297
- )
296
+ it 'merges language configuration' do
297
+ builder.merge_with_hash!(language: :pl)
298
+ expect(builder.config[:language]).to eq({ ui: :pl, content: :pl })
299
+ end
300
+
301
+ it 'preserves existing values when not overridden' do
302
+ builder.version '34.0.0'
303
+ builder.translations :en, :pl
304
+ builder.premium true
305
+
306
+ builder.merge_with_hash!(type: :inline)
307
+
308
+ expect(builder.version).to eq('34.0.0')
309
+ expect(builder.translations).to eq(%i[en pl])
310
+ expect(builder.premium?).to be true
311
+ end
312
+
313
+ it 'merges ckbox configuration' do
314
+ builder.merge_with_hash!(ckbox: { version: '1.0.0', theme: :lark })
315
+ expect(builder.ckbox).to eq({ version: '1.0.0', theme: :lark })
316
+ end
317
+
318
+ it 'merges config options deeply' do
319
+ original_config = { plugins: [:Essentials], toolbar: { items: [:bold] } }
320
+ new_config = { menuBar: { isVisible: true } }
321
+
322
+ builder.merge_with_hash!(config: original_config)
323
+ builder.merge_with_hash!(config: new_config)
324
+
325
+ expect(builder.config[:plugins]).to eq([:Essentials])
326
+ expect(builder.config[:toolbar]).to eq({ items: [:bold] })
327
+ expect(builder.config[:menuBar]).to eq({ isVisible: true })
298
328
  end
299
329
  end
300
330
 
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.16.2
4
+ version: 1.17.1
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-23 00:00:00.000000000 Z
12
+ date: 2024-11-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -82,6 +82,7 @@ files:
82
82
  - spec/e2e/features/context_spec.rb
83
83
  - spec/e2e/features/editor_types_spec.rb
84
84
  - spec/e2e/features/form_integration_spec.rb
85
+ - spec/e2e/features/locale_spec.rb
85
86
  - spec/e2e/spec_helper.rb
86
87
  - spec/e2e/support/eventually.rb
87
88
  - spec/e2e/support/form_helpers.rb
@@ -139,6 +140,7 @@ test_files:
139
140
  - spec/e2e/features/context_spec.rb
140
141
  - spec/e2e/features/editor_types_spec.rb
141
142
  - spec/e2e/features/form_integration_spec.rb
143
+ - spec/e2e/features/locale_spec.rb
142
144
  - spec/e2e/spec_helper.rb
143
145
  - spec/e2e/support/eventually.rb
144
146
  - spec/e2e/support/form_helpers.rb