ckeditor5 0.0.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'url_generator'
4
+ require_relative 'ckeditor_bundle'
5
+ require_relative 'ckbox_bundle'
6
+
7
+ module CKEditor5::Rails
8
+ module Cdn::Helpers
9
+ def ckeditor5_cdn_assets(version:, cdn:, license_key: 'GPL', premium: false, translations: [], ckbox: nil)
10
+ bundle = build_base_cdn_bundle(cdn, version, translations)
11
+ bundle << build_premium_cdn_bundle(cdn, version, translations) if premium
12
+ bundle << build_ckbox_cdn_bundle(ckbox) if ckbox
13
+
14
+ @__ckeditor_context = {
15
+ license_key: license_key,
16
+ bundle: bundle
17
+ }
18
+
19
+ Assets::AssetsBundleHtmlSerializer.new(bundle).to_html
20
+ end
21
+
22
+ Cdn::UrlGenerator::CDN_THIRD_PARTY_GENERATORS.each_key do |key|
23
+ define_method(:"ckeditor5_#{key.to_s.parameterize}_assets") do |**kwargs|
24
+ ckeditor5_cdn_assets(**kwargs.merge(cdn: key))
25
+ end
26
+ end
27
+
28
+ def ckeditor5_assets(**kwargs)
29
+ if kwargs[:license_key] && kwargs[:license_key] != 'GPL'
30
+ ckeditor5_cloud_assets(**kwargs)
31
+ else
32
+ ckeditor5_cdn_assets(**kwargs.merge(cdn: Engine.base.default_cdn))
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def build_base_cdn_bundle(cdn, version, translations)
39
+ Cdn::CKEditorBundle.new(
40
+ Semver.new(version),
41
+ 'ckeditor5',
42
+ translations: translations,
43
+ cdn: cdn
44
+ )
45
+ end
46
+
47
+ def build_premium_cdn_bundle(cdn, version, translations)
48
+ Cdn::CKEditorBundle.new(
49
+ Semver.new(version),
50
+ 'ckeditor5-premium-features',
51
+ translations: translations,
52
+ cdn: cdn
53
+ )
54
+ end
55
+
56
+ def build_ckbox_cdn_bundle(ckbox)
57
+ Cdn::CKBoxBundle.new(
58
+ Semver.new(ckbox[:version]),
59
+ theme: ckbox[:theme] || :lark,
60
+ cdn: ckbox[:cdn] || :ckbox
61
+ )
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+
5
+ module CKEditor5::Rails::Cdn
6
+ module UrlGenerator
7
+ extend ActiveSupport::Concern
8
+
9
+ CDN_THIRD_PARTY_GENERATORS = {
10
+ jsdelivr: lambda { |bundle, version, path|
11
+ base_url = "https://cdn.jsdelivr.net/npm/#{bundle}@#{version}/dist"
12
+ "#{base_url}/#{path.start_with?('translations/') ? '' : 'browser/'}#{path}"
13
+ },
14
+
15
+ unpkg: lambda { |bundle, version, path|
16
+ base_url = "https://unpkg.com/#{bundle}@#{version}/dist"
17
+ "#{base_url}/#{path.start_with?('translations/') ? '' : 'browser/'}#{path}"
18
+ }
19
+ }.freeze
20
+
21
+ CDN_COMMERCIAL_GENERATORS = {
22
+ cloud: ->(bundle, version, path) { "https://cdn.ckeditor.com/#{bundle}/#{version}/#{path}" },
23
+ ckbox: ->(bundle, version, path) { "https://cdn.ckbox.io/#{bundle}/#{version}/#{path}" }
24
+ }.freeze
25
+
26
+ included do
27
+ attr_reader :cdn
28
+ end
29
+
30
+ def create_cdn_url(bundle, version, path)
31
+ generator = CDN_THIRD_PARTY_GENERATORS[cdn] || CDN_COMMERCIAL_GENERATORS[cdn]
32
+
33
+ raise ArgumentError, "Unknown provider: #{cdn}" unless generator
34
+
35
+ generator.call(bundle, version, path)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5::Rails
4
+ module Cloud
5
+ module Helpers
6
+ def ckeditor5_cloud_assets(license_key:, **kwargs)
7
+ raise 'Cloud assets are not permitted in GPL license!' if license_key == 'GPL'
8
+
9
+ ckeditor5_cdn_assets(cdn: :cloud, license_key: license_key, **kwargs)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'props_plugin'
4
+ require_relative 'props'
5
+
6
+ module CKEditor5::Rails
7
+ module Editor::Helpers
8
+ class EditorContextError < StandardError; end
9
+ class PresetNotFoundError < ArgumentError; end
10
+
11
+ def ckeditor5_editor(
12
+ config: nil, extra_config: {},
13
+ type: nil, preset: :default,
14
+ **html_attributes, &block
15
+ )
16
+ context = validate_and_get_editor_context!
17
+ preset = fetch_editor_preset(preset)
18
+
19
+ config ||= preset.config
20
+ type ||= preset.type
21
+
22
+ editor_props = build_editor_props(
23
+ config: config.deep_merge(extra_config),
24
+ type: type,
25
+ context: context
26
+ )
27
+
28
+ render_editor_component(editor_props, html_attributes, &(type == :multiroot ? block : nil))
29
+ end
30
+
31
+ def ckeditor5_editable(name, **kwargs, &block)
32
+ tag.send(:'ckeditor-editable-component', name: name, **kwargs, &block)
33
+ end
34
+
35
+ def ckeditor5_toolbar(**kwargs)
36
+ tag.send(:'ckeditor-toolbar-component', **kwargs)
37
+ end
38
+
39
+ private
40
+
41
+ def validate_and_get_editor_context!
42
+ unless defined?(@__ckeditor_context)
43
+ raise EditorContextError,
44
+ 'CKEditor installation context is not defined. ' \
45
+ 'Ensure ckeditor5_assets is called in the head section.'
46
+ end
47
+
48
+ @__ckeditor_context
49
+ end
50
+
51
+ def fetch_editor_preset(preset)
52
+ Engine.base.presets[preset] or
53
+ raise PresetNotFoundError, "Preset #{preset} is not defined."
54
+ end
55
+
56
+ def build_editor_props(config:, type:, context:)
57
+ Editor::Props.new(context, type, config)
58
+ end
59
+
60
+ def render_editor_component(props, html_attributes, &block)
61
+ tag.send(:'ckeditor-component', **props.to_attributes, **html_attributes, &block)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'props_plugin'
4
+
5
+ module CKEditor5::Rails::Editor
6
+ class Props
7
+ EDITOR_TYPES = {
8
+ classic: 'ClassicEditor',
9
+ inline: 'InlineEditor',
10
+ balloon: 'BalloonEditor',
11
+ decoupled: 'DecoupledEditor',
12
+ multiroot: 'MultiRootEditor'
13
+ }.freeze
14
+
15
+ def initialize(context, type, config)
16
+ raise ArgumentError, "Invalid editor type: #{type}" unless Props.valid_editor_type?(type)
17
+
18
+ @context = context
19
+ @type = type
20
+ @config = config
21
+ end
22
+
23
+ def to_attributes
24
+ {
25
+ type: EDITOR_TYPES[@type],
26
+ **serialized_attributes
27
+ }
28
+ end
29
+
30
+ def self.valid_editor_type?(type)
31
+ EDITOR_TYPES.key?(type)
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :context, :type, :config
37
+
38
+ def serialized_attributes
39
+ {
40
+ translations: serialize_translations,
41
+ plugins: serialize_plugins,
42
+ config: serialize_config
43
+ }
44
+ end
45
+
46
+ def serialize_translations
47
+ context[:bundle].translations_scripts.map { |script| script.import_meta.to_h }.to_json
48
+ end
49
+
50
+ def serialize_plugins
51
+ (config[:plugins] || []).map { |plugin| PropsPlugin.normalize(plugin).to_h }.to_json
52
+ end
53
+
54
+ def serialize_config
55
+ config
56
+ .except(:plugins)
57
+ .merge(licenseKey: context[:license_key] || 'GPL')
58
+ .to_json
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5::Rails::Editor
4
+ class PropsPlugin
5
+ delegate :to_h, to: :import_meta
6
+
7
+ def initialize(name, premium: false)
8
+ @name = name
9
+ @premium = premium
10
+ end
11
+
12
+ def self.normalize(plugin)
13
+ case plugin
14
+ when String, Symbol then new(plugin)
15
+ when PropsPlugin then plugin
16
+ else raise ArgumentError, "Invalid plugin: #{plugin}"
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :name, :premium
23
+
24
+ def import_meta
25
+ ::CKEditor5::Rails::Assets::JSImportMeta.new(
26
+ import_as: name,
27
+ import_name: premium ? 'ckeditor5-premium-features' : 'ckeditor5'
28
+ )
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/engine'
4
+ require_relative 'presets'
5
+
6
+ module CKEditor5::Rails
7
+ class Engine < ::Rails::Engine
8
+ config.ckeditor5 = ActiveSupport::OrderedOptions.new
9
+
10
+ # Specifies which CDN should be used to load CKEditor 5 using the ckeditor5_assets helper.
11
+ # It is possible to use the following CDNs:
12
+ # - :unpkg
13
+ # - :jsdelivr (default)
14
+ config.ckeditor5.default_cdn = :jsdelivr
15
+
16
+ # Specifies configuration of editors generated by gem.
17
+ config.ckeditor5.presets = PresetsManager.new
18
+
19
+ initializer 'helper' do
20
+ ActiveSupport.on_load(:action_view) do
21
+ include Helpers
22
+ end
23
+ end
24
+
25
+ def self.base
26
+ config.ckeditor5
27
+ end
28
+
29
+ def self.configure
30
+ yield config.ckeditor5
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'cdn/helpers'
4
+ require_relative 'cloud/helpers'
5
+ require_relative 'editor/helpers'
6
+
7
+ module CKEditor5::Rails
8
+ module Helpers
9
+ include Cdn::Helpers
10
+ include Cloud::Helpers
11
+ include Editor::Helpers
12
+ end
13
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5::Rails
4
+ class PresetsManager
5
+ attr_reader :presets
6
+
7
+ def initialize
8
+ @presets = {}
9
+ define_default_preset
10
+ end
11
+
12
+ def define(name, &block)
13
+ preset = PresetBuilder.new
14
+ preset.instance_eval(&block)
15
+ @presets[name] = preset
16
+ end
17
+
18
+ def override(name, &block)
19
+ @presets[name].instance_eval(&block)
20
+ end
21
+
22
+ def default
23
+ @presets[:default] || {}
24
+ end
25
+
26
+ def [](name)
27
+ @presets[name] || {}
28
+ end
29
+
30
+ private
31
+
32
+ def define_default_preset
33
+ define :default do
34
+ shape :classic
35
+
36
+ menubar
37
+
38
+ toolbar :undo, :redo, :|, :heading, :|, :bold, :italic, :underline, :|,
39
+ :link, :insertImage, :ckbox, :mediaEmbed, :insertTable, :blockQuote, :|,
40
+ :bulletedList, :numberedList, :todoList, :outdent, :indent
41
+
42
+ plugins :AccessibilityHelp, :Autoformat, :AutoImage, :Autosave,
43
+ :BlockQuote, :Bold, :CKBox, :CKBoxImageEdit, :CloudServices,
44
+ :Essentials, :Heading, :ImageBlock, :ImageCaption, :ImageInline,
45
+ :ImageInsert, :ImageInsertViaUrl, :ImageResize, :ImageStyle,
46
+ :ImageTextAlternative, :ImageToolbar, :ImageUpload, :Indent,
47
+ :IndentBlock, :Italic, :Link, :LinkImage, :List, :ListProperties,
48
+ :MediaEmbed, :Paragraph, :PasteFromOffice, :PictureEditing,
49
+ :SelectAll, :Table, :TableCaption, :TableCellProperties,
50
+ :TableColumnResize, :TableProperties, :TableToolbar,
51
+ :TextTransformation, :TodoList, :Underline, :Undo, :Base64UploadAdapter
52
+ end
53
+ end
54
+ end
55
+
56
+ class PresetBuilder
57
+ attr_reader :type, :config
58
+
59
+ def initialize
60
+ @type = :classic
61
+ @config = {
62
+ plugins: [],
63
+ toolbar: []
64
+ }
65
+ end
66
+
67
+ def shape(type)
68
+ raise ArgumentError, "Invalid editor type: #{type}" unless Editor::Props.valid_editor_type?(type)
69
+
70
+ @type = type
71
+ end
72
+
73
+ def configure(key, value)
74
+ @config[key] = value
75
+ end
76
+
77
+ def menubar(visible: true)
78
+ @config[:menuBar] = {
79
+ isVisible: visible
80
+ }
81
+ end
82
+
83
+ def toolbar(*items)
84
+ @config[:toolbar] = items
85
+ end
86
+
87
+ def plugin(name, premium: false)
88
+ @config[:plugins] << Editor::PropsPlugin.new(name, premium: premium)
89
+ end
90
+
91
+ def plugins(*names, premium: false)
92
+ names.each { |name| plugin(name, premium: premium) }
93
+ end
94
+
95
+ def language(lang)
96
+ @config[:language] = lang
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CKEditor5::Rails::Semver
4
+ attr_reader :version
5
+
6
+ alias to_s :version
7
+
8
+ def initialize(version)
9
+ @version = version
10
+ validate!
11
+ end
12
+
13
+ private
14
+
15
+ def validate!
16
+ raise ArgumentError, 'version must be a string' unless version.is_a?(String)
17
+ raise ArgumentError, 'invalid version format' unless version.match?(/\A\d+\.\d+\.\d+\z/)
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5::Rails
4
+ VERSION = '1.0.1'
5
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CKEditor5
4
+ module Rails
5
+ require_relative 'rails/version'
6
+ require_relative 'rails/semver'
7
+ require_relative 'rails/assets/assets_bundle'
8
+ require_relative 'rails/assets/assets_bundle_html_serializer'
9
+ require_relative 'rails/helpers'
10
+ require_relative 'rails/engine'
11
+ end
12
+ end
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ckeditor5/version'
3
+ require 'ckeditor5/rails'
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: 0.0.1
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mateusz Bagiński
@@ -9,23 +9,50 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-10-09 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2024-10-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '6.0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '6.0'
14
28
  description:
15
29
  email: cziken58@gmail.com
16
30
  executables: []
17
31
  extensions: []
18
- extra_rdoc_files: []
32
+ extra_rdoc_files:
33
+ - README.md
19
34
  files:
20
- - ".github/workflows/ruby.yml"
21
- - ".gitignore"
22
35
  - Gemfile
23
36
  - LICENSE
24
37
  - README.md
25
- - Rakefile
26
- - ckeditor5.gemspec
27
- - lib/ckeditor5.rb
28
- - lib/ckeditor5/version.rb
38
+ - lib/ckeditor5/rails.rb
39
+ - lib/ckeditor5/rails/assets/assets_bundle.rb
40
+ - lib/ckeditor5/rails/assets/assets_bundle_html_serializer.rb
41
+ - lib/ckeditor5/rails/assets/webcomponent.mjs
42
+ - lib/ckeditor5/rails/cdn/ckbox_bundle.rb
43
+ - lib/ckeditor5/rails/cdn/ckeditor_bundle.rb
44
+ - lib/ckeditor5/rails/cdn/helpers.rb
45
+ - lib/ckeditor5/rails/cdn/url_generator.rb
46
+ - lib/ckeditor5/rails/cloud/helpers.rb
47
+ - lib/ckeditor5/rails/editor/helpers.rb
48
+ - lib/ckeditor5/rails/editor/props.rb
49
+ - lib/ckeditor5/rails/editor/props_plugin.rb
50
+ - lib/ckeditor5/rails/engine.rb
51
+ - lib/ckeditor5/rails/helpers.rb
52
+ - lib/ckeditor5/rails/presets.rb
53
+ - lib/ckeditor5/rails/semver.rb
54
+ - lib/ckeditor5/rails/version.rb
55
+ - lib/ckeditor5_rails.rb
29
56
  homepage: https://github.com/Mati365/ckeditor5-rails
30
57
  licenses:
31
58
  - MIT
@@ -38,14 +65,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
38
65
  requirements:
39
66
  - - ">="
40
67
  - !ruby/object:Gem::Version
41
- version: 2.7.0
68
+ version: 3.0.0
42
69
  required_rubygems_version: !ruby/object:Gem::Requirement
43
70
  requirements:
44
71
  - - ">="
45
72
  - !ruby/object:Gem::Version
46
73
  version: '0'
47
74
  requirements: []
48
- rubygems_version: 3.5.16
75
+ rubygems_version: 3.5.22
49
76
  signing_key:
50
77
  specification_version: 4
51
78
  summary: CKEditor 5 for Rails
@@ -1,28 +0,0 @@
1
- name: Ruby
2
-
3
- on:
4
- push:
5
- branches: [ "main" ]
6
- pull_request:
7
- branches: [ "main" ]
8
-
9
- permissions:
10
- contents: read
11
-
12
- jobs:
13
- test:
14
-
15
- runs-on: ubuntu-latest
16
- strategy:
17
- matrix:
18
- ruby-version: ['2.6', '2.7', '3.0']
19
-
20
- steps:
21
- - uses: actions/checkout@v4
22
- - name: Set up Ruby
23
- uses: ruby/setup-ruby@v1
24
- with:
25
- ruby-version: ${{ matrix.ruby-version }}
26
- bundler-cache: true # runs 'bundle install' and caches installed gems automatically
27
- - name: Run tests
28
- run: bundle exec rake
data/.gitignore DELETED
@@ -1,56 +0,0 @@
1
- *.gem
2
- *.rbc
3
- /.config
4
- /coverage/
5
- /InstalledFiles
6
- /pkg/
7
- /spec/reports/
8
- /spec/examples.txt
9
- /test/tmp/
10
- /test/version_tmp/
11
- /tmp/
12
-
13
- # Used by dotenv library to load environment variables.
14
- # .env
15
-
16
- # Ignore Byebug command history file.
17
- .byebug_history
18
-
19
- ## Specific to RubyMotion:
20
- .dat*
21
- .repl_history
22
- build/
23
- *.bridgesupport
24
- build-iPhoneOS/
25
- build-iPhoneSimulator/
26
-
27
- ## Specific to RubyMotion (use of CocoaPods):
28
- #
29
- # We recommend against adding the Pods directory to your .gitignore. However
30
- # you should judge for yourself, the pros and cons are mentioned at:
31
- # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
- #
33
- # vendor/Pods/
34
-
35
- ## Documentation cache and generated files:
36
- /.yardoc/
37
- /_yardoc/
38
- /doc/
39
- /rdoc/
40
-
41
- ## Environment normalization:
42
- /.bundle/
43
- /vendor/bundle
44
- /lib/bundler/man/
45
-
46
- # for a library or gem, you might want to ignore these files since the code is
47
- # intended to run in multiple environments; otherwise, check them in:
48
- # Gemfile.lock
49
- # .ruby-version
50
- # .ruby-gemset
51
-
52
- # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
- .rvmrc
54
-
55
- # Used by RuboCop. Remote config files pulled in from inherit_from directive.
56
- # .rubocop-https?--*
data/Rakefile DELETED
@@ -1,3 +0,0 @@
1
- require 'bundler/gem_tasks'
2
-
3
- task :gem => :build
data/ckeditor5.gemspec DELETED
@@ -1,23 +0,0 @@
1
- lib = File.expand_path('lib', __dir__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
-
4
- require 'ckeditor5/version'
5
-
6
- Gem::Specification.new do |s|
7
- s.name = 'ckeditor5'
8
- s.version = CKEditor5::VERSION
9
- s.platform = Gem::Platform::RUBY
10
- s.summary = 'CKEditor 5 for Rails'
11
- s.authors = [
12
- 'Mateusz Bagiński',
13
- 'Łukasz Modliński'
14
- ]
15
-
16
- s.license = 'MIT'
17
- s.email = 'cziken58@gmail.com'
18
- s.homepage = 'https://github.com/Mati365/ckeditor5-rails'
19
- s.files = `git ls-files`.split("\n")
20
- s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
21
- s.require_paths = ['lib']
22
- s.required_ruby_version = '>= 2.7.0'
23
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CKEditor5
4
- VERSION = '0.0.1'
5
- end