alchemy_cms 6.0.0.b2 → 6.0.0.pre.b6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/README.md +14 -2
  4. data/Rakefile +37 -23
  5. data/app/assets/stylesheets/alchemy/_extends.scss +15 -2
  6. data/app/assets/stylesheets/alchemy/archive.scss +2 -1
  7. data/app/assets/stylesheets/alchemy/fonts.scss +0 -0
  8. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.svg +0 -0
  9. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.ttf +0 -0
  10. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.woff +0 -0
  11. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.svg +0 -0
  12. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.ttf +0 -0
  13. data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.woff +0 -0
  14. data/app/assets/stylesheets/tinymce/skins/alchemy/img/anchor.gif +0 -0
  15. data/app/assets/stylesheets/tinymce/skins/alchemy/img/loader.gif +0 -0
  16. data/app/assets/stylesheets/tinymce/skins/alchemy/img/object.gif +0 -0
  17. data/app/assets/stylesheets/tinymce/skins/alchemy/img/trans.gif +0 -0
  18. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +0 -0
  19. data/app/controllers/alchemy/admin/elements_controller.rb +9 -4
  20. data/app/decorators/alchemy/element_editor.rb +7 -4
  21. data/app/decorators/alchemy/ingredient_editor.rb +5 -1
  22. data/app/helpers/alchemy/elements_block_helper.rb +14 -6
  23. data/app/models/alchemy/element/element_essences.rb +14 -3
  24. data/app/models/alchemy/element/element_ingredients.rb +11 -3
  25. data/app/models/alchemy/element/presenters.rb +9 -2
  26. data/app/models/alchemy/element.rb +0 -14
  27. data/app/models/alchemy/ingredient.rb +16 -62
  28. data/app/models/alchemy/page/page_natures.rb +1 -10
  29. data/app/models/alchemy/page.rb +3 -3
  30. data/app/models/alchemy/page_version.rb +1 -1
  31. data/app/views/alchemy/admin/elements/create.js.erb +1 -1
  32. data/app/views/alchemy/admin/elements/destroy.js.erb +1 -3
  33. data/app/views/alchemy/admin/elements/fold.js.erb +2 -2
  34. data/app/views/alchemy/admin/elements/update.js.erb +1 -1
  35. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  36. data/app/views/alchemy/ingredients/_boolean_editor.html.erb +1 -1
  37. data/app/views/alchemy/ingredients/_file_editor.html.erb +3 -1
  38. data/app/views/alchemy/ingredients/_headline_editor.html.erb +1 -1
  39. data/app/views/alchemy/ingredients/_html_editor.html.erb +1 -1
  40. data/app/views/alchemy/ingredients/_link_editor.html.erb +8 -8
  41. data/app/views/alchemy/ingredients/_node_editor.html.erb +1 -0
  42. data/app/views/alchemy/ingredients/_page_editor.html.erb +1 -0
  43. data/app/views/alchemy/ingredients/_picture_editor.html.erb +7 -6
  44. data/app/views/alchemy/ingredients/_select_editor.html.erb +1 -0
  45. data/app/views/alchemy/ingredients/_text_editor.html.erb +5 -4
  46. data/lib/alchemy/test_support/shared_ingredient_examples.rb +0 -1
  47. data/lib/alchemy/tinymce.rb +4 -0
  48. data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +4 -1
  49. data/lib/alchemy/version.rb +1 -1
  50. data/package.json +1 -1
  51. metadata +4 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50e6a89657c457ab3061bdc6d2cff1eba7ab25856249071e1bbe8c7684e18055
4
- data.tar.gz: 282dd5e51249513e14309c4d98a09822b2fd7d038f8494f3313e00bc1026f8df
3
+ metadata.gz: a2356162437442579cc431fade3fc3486f5262d22e6a6212950634e5ac90f595
4
+ data.tar.gz: 4a933ae8c9652adbe6fef16cf2e420c31160b4352fb2fba3a15f536f67f1dbc0
5
5
  SHA512:
6
- metadata.gz: 54fc70c8b8ba0305d79d3e6309d4dab7a0a050a3aad1d06014fd3f38f9af34f81970a68358a7c3c222d2d740896dccb905920e6a67ee43bfb226d925916b67e6
7
- data.tar.gz: 5d5c5ea2794e1f3c2e84a6b99f4eeb07fe284e98dca598c93361ed5f977b3b4b0e966372f2bba1c32f6b5bf21f8f94ec6cb68bd7b375f6bfb899b295bc724e11
6
+ metadata.gz: 807c2793f1805245bf12512582f2bfd06acdc777a811b070877447792d20b5cfae46b7e04276d90aed455f97fca91f88385df51317a294b9569b7e845017dfbe
7
+ data.tar.gz: 04ec712fe19f499cf0174ee0d044a6c086abec3c063cfa5df32380033de40f4373c9e0978f626a74ac83a67b190ef4154566da152b39e02dba47b15bc6d9e94f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## 6.0.0-b6 (2021-09-02)
2
+
3
+ - Fix element with ingredients preview text [#2187](https://github.com/AlchemyCMS/alchemy_cms/pull/2187) ([tvdeyen](https://github.com/tvdeyen))
4
+ - Do not validate element during toggle fold and create [#2186](https://github.com/AlchemyCMS/alchemy_cms/pull/2186) ([tvdeyen](https://github.com/tvdeyen))
5
+ ## 6.0.0-b5 (2021-08-27)
6
+
7
+ - Remove spec that tests default data store value [#2184](https://github.com/AlchemyCMS/alchemy_cms/pull/2184) ([tvdeyen](https://github.com/tvdeyen))
8
+ - Remove data store accessor from ingredient base class [#2183](https://github.com/AlchemyCMS/alchemy_cms/pull/2183) ([tvdeyen](https://github.com/tvdeyen))
9
+
10
+ ## 6.0.0-b4 (2021-08-27)
11
+
12
+ - Load custom Tinymce config for ingredients [#2182](https://github.com/AlchemyCMS/alchemy_cms/pull/2182) ([tvdeyen](https://github.com/tvdeyen))
13
+ - Fix ingredient editor selector in element update callback [#2181](https://github.com/AlchemyCMS/alchemy_cms/pull/2181) ([tvdeyen](https://github.com/tvdeyen))
14
+ - Ingredient by role block level helper [#2180](https://github.com/AlchemyCMS/alchemy_cms/pull/2180) ([tvdeyen](https://github.com/tvdeyen))
15
+ - Fixes caching [#2179](https://github.com/AlchemyCMS/alchemy_cms/pull/2179) ([tvdeyen](https://github.com/tvdeyen))
16
+ - make images non-executable [#2176](https://github.com/AlchemyCMS/alchemy_cms/pull/2176) ([mensfeld](https://github.com/mensfeld))
17
+ - Release task [#2173](https://github.com/AlchemyCMS/alchemy_cms/pull/2173) ([tvdeyen](https://github.com/tvdeyen))
18
+
19
+ ## 6.0.0.b3 (2021-08-12)
20
+
21
+ ### Fixes
22
+
23
+ - Simplify ingredient creation [#2171](https://github.com/AlchemyCMS/alchemy_cms/pull/2171) ([tvdeyen](https://github.com/tvdeyen))
24
+ - Return ingredients value if element asked for ingredient [#2170](https://github.com/AlchemyCMS/alchemy_cms/pull/2170) ([tvdeyen](https://github.com/tvdeyen))
25
+ - Fix ingredient form field DOM ids [#2167](https://github.com/AlchemyCMS/alchemy_cms/pull/2167) ([tvdeyen](https://github.com/tvdeyen))
26
+ - Ensure resource table ends before the filter/tag sidebar [#2166](https://github.com/AlchemyCMS/alchemy_cms/pull/2166) ([robinboening](https://github.com/robinboening))
27
+ - Return fully namespaced ingredient constant [#2164](https://github.com/AlchemyCMS/alchemy_cms/pull/2164) ([tvdeyen](https://github.com/tvdeyen))
28
+ - (Re)-init Tinymce for elements with ingredients [#2163](https://github.com/AlchemyCMS/alchemy_cms/pull/2163) ([tvdeyen](https://github.com/tvdeyen))
29
+
1
30
  ## 6.0.0.b2 (2021-08-05)
2
31
 
3
32
  ### Features
data/README.md CHANGED
@@ -339,6 +339,10 @@ $ bin/rails s
339
339
 
340
340
  ## 📦 Releasing
341
341
 
342
+ ### Bump version
343
+
344
+ Bump the version number in both `lib/alchemy/version.rb` and `./package.json`. Make sure both are exactly the same and follow [SemVer format](https://semver.org/#semantic-versioning-specification-semver).
345
+
342
346
  ### Update the changelog
343
347
 
344
348
  ```bash
@@ -346,12 +350,20 @@ $ export GITHUB_ACCESS_TOKEN=...
346
350
  $ PREVIOUS_VERSION=4.1.0 bundle exec rake alchemy:changelog:update
347
351
  ```
348
352
 
349
- ### Release a new version
353
+ ### Commit version bump
350
354
 
351
355
  ```bash
352
- $ bundle exec rake release
356
+ $ git commit -am "Bump version to vX.Y.Z"
353
357
  ```
354
358
 
359
+ ### Release a new version
360
+
361
+ This task will publish both the ruby gem and the npm package.
362
+ It also tags the latest commit.
363
+
364
+ ```bash
365
+ $ bundle exec rake alchemy:release
366
+ ```
355
367
 
356
368
  ## ❓Getting Help
357
369
 
data/Rakefile CHANGED
@@ -1,37 +1,37 @@
1
1
  begin
2
- require 'bundler/setup'
2
+ require "bundler/setup"
3
3
  rescue LoadError
4
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
4
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
5
5
  end
6
6
 
7
7
  begin
8
- require 'rdoc/task'
8
+ require "rdoc/task"
9
9
  rescue LoadError
10
- require 'rdoc/rdoc'
11
- require 'rake/rdoctask'
10
+ require "rdoc/rdoc"
11
+ require "rake/rdoctask"
12
12
  RDoc::Task = Rake::RDocTask
13
13
  end
14
14
 
15
- desc 'Generate documentation for Alchemy CMS.'
15
+ desc "Generate documentation for Alchemy CMS."
16
16
  RDoc::Task.new(:rdoc) do |rdoc|
17
- rdoc.rdoc_dir = 'rdoc'
18
- rdoc.title = 'Alchemy CMS'
19
- rdoc.options << '--line-numbers' << '--inline-source'
20
- rdoc.rdoc_files.include('README.md')
21
- rdoc.rdoc_files.include('config/alchemy/*.yml')
22
- rdoc.rdoc_files.include('lib/**/*.rb')
23
- rdoc.rdoc_files.include('app/**/*.rb')
17
+ rdoc.rdoc_dir = "rdoc"
18
+ rdoc.title = "Alchemy CMS"
19
+ rdoc.options << "--line-numbers" << "--inline-source"
20
+ rdoc.rdoc_files.include("README.md")
21
+ rdoc.rdoc_files.include("config/alchemy/*.yml")
22
+ rdoc.rdoc_files.include("lib/**/*.rb")
23
+ rdoc.rdoc_files.include("app/**/*.rb")
24
24
  end
25
25
 
26
- APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
27
- load 'rails/tasks/engine.rake'
26
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
27
+ load "rails/tasks/engine.rake"
28
28
 
29
- require 'rspec/core'
30
- require 'rspec/core/rake_task'
29
+ require "rspec/core"
30
+ require "rspec/core/rake_task"
31
31
 
32
32
  RSpec::Core::RakeTask.new(:spec)
33
33
 
34
- task default: ['alchemy:spec:prepare', :spec]
34
+ task default: ["alchemy:spec:prepare", :spec]
35
35
 
36
36
  Bundler::GemHelper.install_tasks
37
37
 
@@ -56,11 +56,11 @@ namespace :alchemy do
56
56
  namespace :changelog do
57
57
  desc "Update CHANGELOG from GitHub (Set GITHUB_ACCESS_TOKEN and PREVIOUS_VERSION to a version you want to write changelog changes for)"
58
58
  task :update do
59
- original_file = './CHANGELOG.md'
60
- new_file = original_file + '.new'
61
- backup = original_file + '.old'
62
- changes = `git rev-list v#{ENV['PREVIOUS_VERSION']}..HEAD | bundle exec github_fast_changelog AlchemyCMS/alchemy_cms`
63
- File.open(new_file, 'w') do |fo|
59
+ original_file = "./CHANGELOG.md"
60
+ new_file = original_file + ".new"
61
+ backup = original_file + ".old"
62
+ changes = `git rev-list v#{ENV["PREVIOUS_VERSION"]}..HEAD | bundle exec github_fast_changelog AlchemyCMS/alchemy_cms`
63
+ File.open(new_file, "w") do |fo|
64
64
  fo.puts changes
65
65
  File.foreach(original_file) do |li|
66
66
  fo.puts li
@@ -72,4 +72,18 @@ namespace :alchemy do
72
72
  File.delete(backup)
73
73
  end
74
74
  end
75
+
76
+ desc "Release a new Ruby gem and npm package in one command"
77
+ task :release do
78
+ require "json"
79
+ require_relative "lib/alchemy/version"
80
+ package = File.read("package.json")
81
+ unless JSON.parse(package)["version"] == Alchemy.version
82
+ abort "Ruby gem and npm package versions are out of sync! Please fix."
83
+ end
84
+ # Release the Ruby gem with bundler
85
+ Rake::Task["release"].invoke
86
+ # Publish npm package via CLI
87
+ system "npm publish"
88
+ end
75
89
  end
@@ -31,15 +31,28 @@
31
31
  line-height: $form-field-line-height;
32
32
  transition: $transition-duration;
33
33
 
34
- &:focus {
34
+ &:focus:not(.readonly) {
35
35
  @include default-focus-style($box-shadow: 0 0 0 1px $focus-color);
36
36
  }
37
37
 
38
- &[disabled], .disabled {
38
+ &[disabled],
39
+ &.disabled,
40
+ &[readonly],
41
+ &.readonly {
39
42
  color: $form-field-disabled-text-color;
40
43
  background-color: $form-field-disabled-bg-color;
44
+ cursor: default;
45
+ }
46
+
47
+ &[disabled],
48
+ &.disabled {
41
49
  cursor: not-allowed;
42
50
  }
51
+
52
+ &[readonly],
53
+ &.readonly {
54
+ pointer-events: none;
55
+ }
43
56
  }
44
57
 
45
58
  %gradiated-toolbar {
@@ -20,7 +20,8 @@
20
20
  padding-bottom: 60px;
21
21
 
22
22
  &.with_tag_filter {
23
- padding-right: 242px;
23
+ width: calc(100% - 235px);
24
+ overflow-x: auto;
24
25
  }
25
26
  }
26
27
 
File without changes
@@ -32,14 +32,14 @@ module Alchemy
32
32
  if @paste_from_clipboard = params[:paste_from_clipboard].present?
33
33
  @element = paste_element_from_clipboard
34
34
  else
35
- @element = Element.create(create_element_params)
35
+ @element = Element.new(create_element_params)
36
36
  end
37
37
  if @page.definition["insert_elements_at"] == "top"
38
38
  @insert_at_top = true
39
- @element.move_to_top
39
+ @element.position = 1
40
40
  end
41
41
  end
42
- if @element.valid?
42
+ if @element.save
43
43
  render :create
44
44
  else
45
45
  @element.page_version = @page_version
@@ -65,6 +65,7 @@ module Alchemy
65
65
  end
66
66
 
67
67
  def destroy
68
+ @richtext_ids = @element.richtext_contents_ids + @element.richtext_ingredients_ids
68
69
  @element.destroy
69
70
  @notice = Alchemy.t("Successfully deleted element") % { element: @element.display_name }
70
71
  end
@@ -90,10 +91,14 @@ module Alchemy
90
91
  end
91
92
  end
92
93
 
94
+ # Toggle fodls the element and persists the state in the db
95
+ #
96
+ # Ingredient validations might make the element invalid.
97
+ # In this case we are just toggling a UI state and do not care about the validations.
93
98
  def fold
94
99
  @page = @element.page
95
100
  @element.folded = !@element.folded
96
- @element.save
101
+ @element.save(validate: false)
97
102
  end
98
103
 
99
104
  private
@@ -26,7 +26,7 @@ module Alchemy
26
26
  # @return Array<Alchemy::IngredientEditor>
27
27
  def ingredients
28
28
  element.definition.fetch(:ingredients, []).map do |ingredient|
29
- Alchemy::IngredientEditor.new(find_or_create_ingredient(ingredient[:role]))
29
+ Alchemy::IngredientEditor.new(find_or_create_ingredient(ingredient))
30
30
  end
31
31
  end
32
32
 
@@ -121,9 +121,12 @@ module Alchemy
121
121
  Alchemy::Content.create(element: element, name: name)
122
122
  end
123
123
 
124
- def find_or_create_ingredient(role)
125
- element.ingredients.find { |i| i.role == role } ||
126
- Ingredient.create(element: element, role: role)
124
+ def find_or_create_ingredient(definition)
125
+ element.ingredients.detect { |i| i.role == definition[:role] } ||
126
+ element.ingredients.create!(
127
+ role: definition[:role],
128
+ type: Alchemy::Ingredient.normalize_type(definition[:type]),
129
+ )
127
130
  end
128
131
  end
129
132
  end
@@ -64,8 +64,12 @@ module Alchemy
64
64
  "element[ingredients_attributes][#{form_field_counter}][#{column}]"
65
65
  end
66
66
 
67
+ # Returns a unique string to be passed to a form field id.
68
+ #
69
+ # @param column [String] A Ingredient column_name. Default is 'value'
70
+ #
67
71
  def form_field_id(column = "value")
68
- "element_ingredients_attributes_#{form_field_counter}_#{column}"
72
+ "element_#{element.id}_ingredient_#{id}_#{column}"
69
73
  end
70
74
 
71
75
  # Fixes Rails partial renderer calling to_model on the object
@@ -51,21 +51,23 @@ module Alchemy
51
51
  # If the element uses +ingredients+ it returns the +value+ of the ingredient record.
52
52
  #
53
53
  def ingredient(name)
54
- element.ingredient(name).presence || element.ingredient_by_role(name)&.value
54
+ element.ingredient(name)
55
55
  end
56
56
 
57
- deprecate ingredient: :value, deprecator: Alchemy::Deprecation
58
-
59
57
  # Returns the value of one of the element's ingredients.
60
58
  #
61
59
  def value(name)
62
- element.ingredient_by_role(name)&.value
60
+ element.value_for(name)
63
61
  end
64
62
 
65
- # Returns true if the given content or ingredient has been filled by the user.
63
+ # Returns true if the given content or ingredient has a value.
66
64
  #
67
65
  def has?(name)
68
- element.has_ingredient?(name) || element.has_value_for?(name)
66
+ if element.ingredient_definitions.any?
67
+ element.has_value_for?(name)
68
+ else
69
+ element.has_ingredient?(name)
70
+ end
69
71
  end
70
72
 
71
73
  # Return's the given content's essence.
@@ -75,6 +77,12 @@ module Alchemy
75
77
  end
76
78
 
77
79
  deprecate essence: "Use `ingredient_by_role` instead", deprecator: Alchemy::Deprecation
80
+
81
+ # Return's the ingredient record by given role.
82
+ #
83
+ def ingredient_by_role(role)
84
+ element.ingredient_by_role(role)
85
+ end
78
86
  end
79
87
 
80
88
  # Block-level helper for element views. Constructs a DOM element wrapping
@@ -5,10 +5,20 @@ module Alchemy
5
5
  module ElementEssences
6
6
  # Returns the contents essence value (aka. ingredient) for passed content name.
7
7
  def ingredient(name)
8
- content = content_by_name(name)
9
- return nil if content.blank?
8
+ ing = ingredient_by_role(name)
9
+ if ing
10
+ Alchemy::Deprecation.warn <<~WARN
11
+ Using `element.ingredient` to get the value of an ingredient is deprecated and will change in Alchemy 6.1
12
+ If you want to read the value of an elements ingredient please use `element.value_for(:ingredient_role)` instead.
13
+ The next version of Alchemy will return a `Alchemy::Ingredient` record instead.
14
+ WARN
15
+ ing.value
16
+ else
17
+ content = content_by_name(name)
18
+ return nil if content.blank?
10
19
 
11
- content.ingredient
20
+ content.ingredient
21
+ end
12
22
  end
13
23
 
14
24
  # True if the element has a content for given name,
@@ -16,6 +26,7 @@ module Alchemy
16
26
  def has_ingredient?(name)
17
27
  ingredient(name).present?
18
28
  end
29
+ deprecate has_ingredient?: :has_value_for?, deprecator: Alchemy::Deprecation
19
30
 
20
31
  # Returns all essence errors in the format of:
21
32
  #
@@ -22,6 +22,11 @@ module Alchemy
22
22
  validates_associated :ingredients, on: :update
23
23
  end
24
24
 
25
+ # The value of an ingredient of the element by role
26
+ def value_for(role)
27
+ ingredient_by_role(role)&.value
28
+ end
29
+
25
30
  # Find first ingredient from element by given role.
26
31
  def ingredient_by_role(role)
27
32
  ingredients.detect { |ingredient| ingredient.role == role.to_s }
@@ -87,7 +92,7 @@ module Alchemy
87
92
  # True if the element has a ingredient for given name
88
93
  # that has a non blank value.
89
94
  def has_value_for?(role)
90
- ingredient_by_role(role)&.value.present?
95
+ value_for(role).present?
91
96
  end
92
97
 
93
98
  # Ingredient validation error messages
@@ -167,8 +172,11 @@ module Alchemy
167
172
 
168
173
  # Builds ingredients for this element as described in the +elements.yml+
169
174
  def build_ingredients
170
- self.ingredients = ingredient_definitions.map do |attributes|
171
- Ingredient.build(role: attributes[:role], element: self)
175
+ ingredient_definitions.each do |attributes|
176
+ ingredients.build(
177
+ role: attributes[:role],
178
+ type: Alchemy::Ingredient.normalize_type(attributes[:type]),
179
+ )
172
180
  end
173
181
  end
174
182
  end
@@ -99,12 +99,12 @@ module Alchemy
99
99
  # The ingredient that's used for element's preview text.
100
100
  #
101
101
  # It tries to find one of element's ingredients that is defined +as_element_title+.
102
- # Takes element's first ingredient if no ingredient is defined +as_element_title+.
102
+ # Takes element's first defined ingredient if no ingredient is defined +as_element_title+.
103
103
  #
104
104
  # @return (Alchemy::Ingredient)
105
105
  #
106
106
  def preview_ingredient
107
- @_preview_ingredient ||= ingredients.detect(&:preview_ingredient?) || ingredients.first
107
+ @_preview_ingredient ||= ingredients.detect(&:preview_ingredient?) || first_ingredient_by_definition
108
108
  end
109
109
 
110
110
  private
@@ -122,6 +122,13 @@ module Alchemy
122
122
  def preview_text_from_preview_ingredient(maxlength)
123
123
  preview_ingredient&.preview_text(maxlength)
124
124
  end
125
+
126
+ def first_ingredient_by_definition
127
+ return if ingredient_definitions.empty?
128
+
129
+ role = ingredient_definitions.first["role"]
130
+ ingredients.detect { |ingredient| ingredient.role == role }
131
+ end
125
132
  end
126
133
  end
127
134
  end
@@ -267,20 +267,6 @@ module Alchemy
267
267
  "alchemy/elements/#{name}"
268
268
  end
269
269
 
270
- # Returns the key that's taken for cache path.
271
- #
272
- # Uses the page's +published_at+ value that's updated when the user publishes the page.
273
- #
274
- # If the page is the current preview it uses the element's updated_at value as cache key.
275
- #
276
- def cache_key
277
- if Page.current_preview == page
278
- "alchemy/elements/#{id}-#{updated_at}"
279
- else
280
- "alchemy/elements/#{id}-#{page.published_at}"
281
- end
282
- end
283
-
284
270
  # A collection of element names that can be nested inside this element.
285
271
  def nestable_elements
286
272
  definition.fetch("nestable_elements", [])
@@ -6,12 +6,13 @@ module Alchemy
6
6
 
7
7
  include Hints
8
8
 
9
- self.abstract_class = true
10
9
  self.table_name = "alchemy_ingredients"
11
10
 
12
11
  belongs_to :element, touch: true, class_name: "Alchemy::Element", inverse_of: :ingredients
13
12
  belongs_to :related_object, polymorphic: true, optional: true
14
13
 
14
+ before_validation(on: :create) { self.value ||= default_value }
15
+
15
16
  validates :type, presence: true
16
17
  validates :role, presence: true
17
18
 
@@ -33,32 +34,6 @@ module Alchemy
33
34
  scope :videos, -> { where(type: "Alchemy::Ingredients::Video") }
34
35
 
35
36
  class << self
36
- # Builds concrete ingredient class as described in the +elements.yml+
37
- def build(attributes = {})
38
- element = attributes[:element]
39
- raise ArgumentError, "No element given. Please pass element in attributes." if element.nil?
40
- raise ArgumentError, "No role given. Please pass role in attributes." if attributes[:role].nil?
41
-
42
- definition = element.ingredient_definition_for(attributes[:role])
43
- if definition.nil?
44
- raise DefinitionError,
45
- "No definition found for #{attributes[:role]}. Please define #{attributes[:role]} on #{element[:name]}."
46
- end
47
-
48
- ingredient_class = Ingredient.ingredient_class_by_type(definition[:type])
49
- ingredient_class.new(
50
- type: Ingredient.normalize_type(definition[:type]),
51
- value: default_value(definition),
52
- role: definition[:role],
53
- element: element,
54
- )
55
- end
56
-
57
- # Creates concrete ingredient class as described in the +elements.yml+
58
- def create(attributes = {})
59
- build(attributes).tap(&:save)
60
- end
61
-
62
37
  # Defines getter and setter method aliases for related object
63
38
  #
64
39
  # @param [String|Symbol] The name of the alias
@@ -78,20 +53,6 @@ module Alchemy
78
53
  end
79
54
  end
80
55
 
81
- # Returns an ingredient class by type
82
- #
83
- # Raises ArgumentError if there is no such class in the
84
- # +Alchemy::Ingredients+ module namespace.
85
- #
86
- # If you add custom ingredient class,
87
- # put them in the +Alchemy::Ingredients+ module namespace
88
- #
89
- # @param [String] The ingredient class name to constantize
90
- # @return [Class]
91
- def ingredient_class_by_type(ingredient_type)
92
- Alchemy::Ingredients.const_get(ingredient_type.to_s.classify.demodulize)
93
- end
94
-
95
56
  # Modulize ingredient type
96
57
  #
97
58
  # Makes sure the passed ingredient type is in the +Alchemy::Ingredients+
@@ -112,22 +73,6 @@ module Alchemy
112
73
  default: Alchemy.t("ingredient_roles.#{role}", default: role.humanize),
113
74
  )
114
75
  end
115
-
116
- private
117
-
118
- # Returns the default value from ingredient definition
119
- #
120
- # If the value is a symbol it gets passed through i18n
121
- # inside the +alchemy.default_ingredient_texts+ scope
122
- def default_value(definition)
123
- default = definition[:default]
124
- case default
125
- when Symbol
126
- Alchemy.t(default, scope: :default_ingredient_texts)
127
- else
128
- default
129
- end
130
- end
131
76
  end
132
77
 
133
78
  # Compatibility method for access from element
@@ -173,11 +118,6 @@ module Alchemy
173
118
  value.to_s[0..maxlength - 1]
174
119
  end
175
120
 
176
- # Cross DB adapter data accessor that works
177
- def data
178
- @_data ||= (self[:data] || {}).with_indifferent_access
179
- end
180
-
181
121
  # The path to the view partial of the ingredient
182
122
  # @return [String]
183
123
  def to_partial_path
@@ -220,5 +160,19 @@ module Alchemy
220
160
  def hint_translation_attribute
221
161
  role
222
162
  end
163
+
164
+ # Returns the default value from ingredient definition
165
+ #
166
+ # If the value is a symbol it gets passed through i18n
167
+ # inside the +alchemy.default_ingredient_texts+ scope
168
+ def default_value
169
+ default = definition[:default]
170
+ case default
171
+ when Symbol
172
+ Alchemy.t(default, scope: :default_ingredient_texts)
173
+ else
174
+ default
175
+ end
176
+ end
223
177
  end
224
178
  end
@@ -110,22 +110,13 @@ module Alchemy
110
110
  # If the page is the current preview it uses the updated_at value as cache key.
111
111
  #
112
112
  def cache_key
113
- if Page.current_preview == self
113
+ if Page.current_preview == id
114
114
  "alchemy/pages/#{id}-#{updated_at}"
115
115
  else
116
116
  "alchemy/pages/#{id}-#{published_at}"
117
117
  end
118
118
  end
119
119
 
120
- # We use the published_at value for the cache_key.
121
- #
122
- # If no published_at value is set yet, i.e. because it was never published,
123
- # we return the updated_at value.
124
- #
125
- def published_at
126
- read_attribute(:published_at) || updated_at
127
- end
128
-
129
120
  # Returns true if the page cache control headers should be set.
130
121
  #
131
122
  # == Disable Alchemy's page caching globally
@@ -198,13 +198,13 @@ module Alchemy
198
198
  %w[name urlname title]
199
199
  end
200
200
 
201
- # Used to store the current page previewed in the edit page template.
201
+ # Used to store the current page id previewed in the edit page template.
202
202
  #
203
203
  def current_preview=(page)
204
- RequestStore.store[:alchemy_current_preview] = page
204
+ RequestStore.store[:alchemy_current_preview] = page&.id
205
205
  end
206
206
 
207
- # Returns the current page previewed in the edit page template.
207
+ # Returns the current page id previewed in the edit page template.
208
208
  #
209
209
  def current_preview
210
210
  RequestStore.store[:alchemy_current_preview]
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Alchemy
4
4
  class PageVersion < BaseRecord
5
- belongs_to :page, class_name: "Alchemy::Page", inverse_of: :versions
5
+ belongs_to :page, class_name: "Alchemy::Page", inverse_of: :versions, touch: true
6
6
 
7
7
  has_many :elements, -> { order(:position) },
8
8
  class_name: "Alchemy::Element",
@@ -34,7 +34,7 @@
34
34
 
35
35
  Alchemy.growl('<%= Alchemy.t(:successfully_added_element) %>');
36
36
  Alchemy.closeCurrentDialog();
37
- Alchemy.Tinymce.init(<%= @element.richtext_contents_ids.to_json %>);
37
+ Alchemy.Tinymce.init(<%= (@element.richtext_contents_ids + @element.richtext_ingredients_ids).to_json %>);
38
38
  Alchemy.PreviewWindow.refresh(function() {
39
39
  Alchemy.ElementEditors.focusElementPreview(<%= @element.id %>);
40
40
  });
@@ -3,9 +3,7 @@ $('#element_<%= @element.id %>').hide(200, function() {
3
3
  Alchemy.growl('<%= j @notice %>');
4
4
  $('#element_area .sortable-elements').sortable('refresh');
5
5
  Alchemy.PreviewWindow.refresh();
6
- <% @element.richtext_contents_ids.each do |id| %>
7
- tinymce.get('tinymce_<%= id %>').remove();
8
- <% end %>
6
+ Alchemy.Tinymce.remove(<%= @richtext_ids.to_json %>);
9
7
  <% if @element.fixed? %>
10
8
  Alchemy.FixedElements.removeTab(<%= @element.id %>);
11
9
  <% end %>
@@ -14,12 +14,12 @@
14
14
 
15
15
  <% if @element.folded? -%>
16
16
 
17
- Alchemy.Tinymce.remove(<%= @element.richtext_contents_ids.to_json %>);
17
+ Alchemy.Tinymce.remove(<%= (@element.richtext_contents_ids + @element.richtext_ingredients_ids).to_json %>);
18
18
 
19
19
  <% else -%>
20
20
 
21
21
  $el.trigger('FocusElementEditor.Alchemy');
22
- Alchemy.Tinymce.init(<%= @element.richtext_contents_ids.to_json %>);
22
+ Alchemy.Tinymce.init(<%= (@element.richtext_contents_ids + @element.richtext_ingredients_ids).to_json %>);
23
23
  Alchemy.GUI.initElement($el);
24
24
  Alchemy.SortableElements(
25
25
  <%= @page.id %>,
@@ -1,7 +1,7 @@
1
1
  (function() {
2
2
  var $el = $('#element_<%= @element.id %>');
3
3
  var $errors = $('#element_<%= @element.id %>_errors');
4
- $('> .element-content .content_editor, > .element-content .ingredient_editor', $el).removeClass('validation_failed');
4
+ $('> .element-content .content_editor, > .element-content .ingredient-editor', $el).removeClass('validation_failed');
5
5
 
6
6
  <%- if @element_validated -%>
7
7
 
@@ -138,7 +138,7 @@
138
138
  <% end %>
139
139
 
140
140
  <% content_for :javascripts do %>
141
- <% if Alchemy::Tinymce.custom_config_contents(@page).present? %>
141
+ <% if Alchemy::Tinymce.custom_configs_present?(@page) %>
142
142
  <%= render 'tinymce_custom_config' %>
143
143
  <% end %>
144
144
 
@@ -3,7 +3,7 @@
3
3
  data: boolean_editor.data_attributes do %>
4
4
  <%= element_form.fields_for(:ingredients, boolean_editor.ingredient) do |f| %>
5
5
  <%= f.label :value, style: "display: inline-block" do %>
6
- <%= f.check_box :value %>
6
+ <%= f.check_box :value, id: nil %>
7
7
  <%= render_ingredient_role(boolean_editor) %>
8
8
  <% end %>
9
9
  <%= render_hint_for(boolean_editor) %>
@@ -44,7 +44,9 @@
44
44
  },
45
45
  title: Alchemy.t(:edit_file_properties) %>
46
46
  </div>
47
- <%= f.hidden_field :attachment_id, value: file_editor.attachment&.id %>
47
+ <%= f.hidden_field :attachment_id,
48
+ value: file_editor.attachment&.id,
49
+ id: file_editor.form_field_id(:attachment_id) %>
48
50
  </div>
49
51
  <% end %>
50
52
  <% end %>
@@ -3,7 +3,7 @@
3
3
  data: headline_editor.data_attributes do %>
4
4
  <%= element_form.fields_for(:ingredients, headline_editor.ingredient) do |f| %>
5
5
  <%= ingredient_label(headline_editor) %>
6
- <%= f.text_field :value %>
6
+ <%= f.text_field :value, id: nil %>
7
7
 
8
8
  <div class="input-row">
9
9
  <% if headline_editor.level_options.length > 1 %>
@@ -3,6 +3,6 @@
3
3
  data: html_editor.data_attributes do %>
4
4
  <%= element_form.fields_for(:ingredients, html_editor.ingredient) do |f| %>
5
5
  <%= ingredient_label(html_editor) %>
6
- <%= f.text_area :value %>
6
+ <%= f.text_area :value, id: nil %>
7
7
  <% end %>
8
8
  <% end %>
@@ -4,15 +4,15 @@
4
4
  <%= element_form.fields_for(:ingredients, link_editor.ingredient) do |f| %>
5
5
  <%= ingredient_label(link_editor) %>
6
6
  <%= f.text_field :value,
7
- class: "thin_border text_with_icon disabled",
8
- name: nil,
9
- id: nil,
10
- disabled: true
7
+ class: "thin_border text_with_icon readonly",
8
+ id: link_editor.form_field_id,
9
+ "data-link-value": true,
10
+ readonly: true,
11
+ tabindex: -1
11
12
  %>
12
- <%= f.hidden_field :value, "data-link-value": true %>
13
- <%= f.hidden_field :link_title, "data-link-title": true %>
14
- <%= f.hidden_field :link_class_name, "data-link-class": true %>
15
- <%= f.hidden_field :link_target, "data-link-target": true %>
13
+ <%= f.hidden_field :link_title, "data-link-title": true, id: nil %>
14
+ <%= f.hidden_field :link_class_name, "data-link-class": true, id: nil %>
15
+ <%= f.hidden_field :link_target, "data-link-target": true, id: nil %>
16
16
  <% end %>
17
17
  <%= render "alchemy/ingredients/shared/link_tools", ingredient_editor: link_editor %>
18
18
  <% end %>
@@ -5,6 +5,7 @@
5
5
  <%= ingredient_label(node_editor, :node_id) %>
6
6
  <%= f.text_field :node_id,
7
7
  value: node_editor.node&.id,
8
+ id: node_editor.form_field_id(:node_id),
8
9
  class: 'alchemy_selectbox full_width' %>
9
10
  <% end %>
10
11
  <% end %>
@@ -5,6 +5,7 @@
5
5
  <%= ingredient_label(page_editor, :page_id) %>
6
6
  <%= f.text_field :page_id,
7
7
  value: page_editor.page&.id,
8
+ id: page_editor.form_field_id(:page_id),
8
9
  class: 'alchemy_selectbox full_width' %>
9
10
  <% end %>
10
11
  <% end %>
@@ -44,16 +44,17 @@
44
44
  </div>
45
45
  <% end %>
46
46
  <%= f.hidden_field :picture_id, value: picture_editor.picture&.id,
47
+ id: picture_editor.form_field_id(:picture_id),
47
48
  data: {
48
49
  picture_id: true,
49
50
  image_file_width: picture_editor.image_file_width,
50
51
  image_file_height: picture_editor.image_file_height
51
52
  } %>
52
- <%= f.hidden_field :link, data: { link_value: true } %>
53
- <%= f.hidden_field :link_title, data: { link_title: true } %>
54
- <%= f.hidden_field :link_class_name, data: { link_class: true } %>
55
- <%= f.hidden_field :link_target, data: { link_target: true } %>
56
- <%= f.hidden_field :crop_from, data: { crop_from: true } %>
57
- <%= f.hidden_field :crop_size, data: { crop_size: true } %>
53
+ <%= f.hidden_field :link, data: { link_value: true }, id: nil %>
54
+ <%= f.hidden_field :link_title, data: { link_title: true }, id: nil %>
55
+ <%= f.hidden_field :link_class_name, data: { link_class: true }, id: nil %>
56
+ <%= f.hidden_field :link_target, data: { link_target: true }, id: nil %>
57
+ <%= f.hidden_field :crop_from, data: { crop_from: true }, id: nil %>
58
+ <%= f.hidden_field :crop_size, data: { crop_size: true }, id: nil %>
58
59
  <% end %>
59
60
  <% end %>
@@ -22,6 +22,7 @@
22
22
  options_tags = options_for_select(select_values, select_editor.value)
23
23
  end %>
24
24
  <%= f.select :value, options_tags, {}, {
25
+ id: nil,
25
26
  class: ["alchemy_selectbox", "ingredient-editor-select"]
26
27
  } %>
27
28
  <% end %>
@@ -7,12 +7,13 @@
7
7
  <%= ingredient_label(text_editor) %>
8
8
  <%= f.text_field :value,
9
9
  class: text_editor.settings[:linkable] ? "text_with_icon" : "",
10
+ id: nil,
10
11
  type: text_editor.settings[:input_type] || "text" %>
11
12
  <% if text_editor.settings[:linkable] %>
12
- <%= f.hidden_field :link, "data-link-value": true %>
13
- <%= f.hidden_field :link_title, "data-link-title": true %>
14
- <%= f.hidden_field :link_class_name, "data-link-class": true%>
15
- <%= f.hidden_field :link_target, "data-link-target": true %>
13
+ <%= f.hidden_field :link, "data-link-value": true, id: nil %>
14
+ <%= f.hidden_field :link_title, "data-link-title": true, id: nil %>
15
+ <%= f.hidden_field :link_class_name, "data-link-class": true, id: nil %>
16
+ <%= f.hidden_field :link_target, "data-link-target": true, id: nil %>
16
17
  <%= render "alchemy/ingredients/shared/link_tools", ingredient_editor: text_editor %>
17
18
  <% end %>
18
19
  <% end %>
@@ -16,7 +16,6 @@ RSpec.shared_examples_for "an alchemy ingredient" do
16
16
  it { is_expected.to belong_to(:related_object).optional }
17
17
  it { is_expected.to validate_presence_of(:role) }
18
18
  it { is_expected.to validate_presence_of(:type) }
19
- it { expect(subject.data).to eq({}) }
20
19
 
21
20
  describe "#settings" do
22
21
  subject { ingredient.settings }
@@ -34,6 +34,10 @@ module Alchemy
34
34
  @@init
35
35
  end
36
36
 
37
+ def custom_configs_present?(page)
38
+ custom_config_contents(page).any? || custom_config_ingredients(page).any?
39
+ end
40
+
37
41
  def custom_config_contents(page)
38
42
  content_definitions_from_elements(page.descendent_element_definitions)
39
43
  end
@@ -30,7 +30,10 @@ module Alchemy::Upgrader::Tasks
30
30
  next unless content
31
31
 
32
32
  essence = content.essence
33
- ingredient = Alchemy::Ingredient.build(role: ingredient_definition[:role], element: element)
33
+ ingredient = element.ingredients.build(
34
+ role: ingredient_definition[:role],
35
+ type: Alchemy::Ingredient.normalize_type(ingredient_definition[:type]),
36
+ )
34
37
  belongs_to_associations = essence.class.reflect_on_all_associations(:belongs_to)
35
38
  if belongs_to_associations.any?
36
39
  ingredient.related_object = essence.public_send(belongs_to_associations.first.name)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "6.0.0.b2"
4
+ VERSION = "6.0.0-b6"
5
5
 
6
6
  def self.version
7
7
  VERSION
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alchemy_cms/admin",
3
- "version": "6.0.0-b2",
3
+ "version": "6.0.0-b6",
4
4
  "description": "AlchemyCMS",
5
5
  "browser": "package/admin.js",
6
6
  "files": [
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0.b2
4
+ version: 6.0.0.pre.b6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen
@@ -10,10 +10,10 @@ authors:
10
10
  - Hendrik Mans
11
11
  - Carsten Fregin
12
12
  - Martin Meyerhoff
13
- autorequire:
13
+ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2021-08-05 00:00:00.000000000 Z
16
+ date: 2021-09-02 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: actionmailer
@@ -1517,8 +1517,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1517
1517
  requirements:
1518
1518
  - ImageMagick (libmagick), v6.6 or greater.
1519
1519
  rubygems_version: 3.1.6
1520
- signing_key:
1520
+ signing_key:
1521
1521
  specification_version: 4
1522
1522
  summary: A powerful, userfriendly and flexible CMS for Rails
1523
1523
  test_files: []
1524
- ...