alchemy_cms 6.0.14 → 6.1.0

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.

Potentially problematic release.


This version of alchemy_cms might be problematic. Click here for more details.

Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +0 -3
  3. data/.github/workflows/stale.yml +2 -0
  4. data/CHANGELOG.md +34 -5
  5. data/Gemfile +2 -2
  6. data/alchemy_cms.gemspec +2 -1
  7. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +13 -11
  8. data/app/assets/stylesheets/alchemy/_variables.scss +9 -4
  9. data/app/assets/stylesheets/alchemy/elements.scss +96 -4
  10. data/app/assets/stylesheets/alchemy/forms.scss +59 -17
  11. data/app/assets/stylesheets/tinymce/skins/alchemy/content.min.css.scss +3 -3
  12. data/app/controllers/alchemy/admin/ingredients_controller.rb +1 -1
  13. data/app/controllers/alchemy/admin/pages_controller.rb +3 -3
  14. data/app/controllers/alchemy/api/ingredients_controller.rb +22 -0
  15. data/app/controllers/alchemy/messages_controller.rb +1 -1
  16. data/app/controllers/alchemy/pages_controller.rb +19 -5
  17. data/app/decorators/alchemy/ingredient_editor.rb +4 -0
  18. data/app/helpers/alchemy/elements_helper.rb +0 -8
  19. data/app/helpers/alchemy/url_helper.rb +0 -8
  20. data/app/models/alchemy/element/definitions.rb +16 -2
  21. data/app/models/alchemy/element/dom_id.rb +30 -0
  22. data/app/models/alchemy/element/presenters.rb +1 -1
  23. data/app/models/alchemy/element.rb +12 -3
  24. data/app/models/alchemy/ingredients/headline.rb +4 -1
  25. data/app/models/alchemy/ingredients/text.rb +3 -0
  26. data/app/models/alchemy/page/page_layouts.rb +128 -0
  27. data/app/models/alchemy/page.rb +4 -2
  28. data/app/models/alchemy/picture_thumb/create.rb +1 -1
  29. data/app/models/concerns/alchemy/dom_ids.rb +32 -0
  30. data/app/serializers/alchemy/ingredient_serializer.rb +11 -0
  31. data/app/views/alchemy/admin/elements/update.js.erb +3 -0
  32. data/app/views/alchemy/admin/ingredients/_dom_id_fields.html.erb +4 -0
  33. data/app/views/alchemy/admin/ingredients/_headline_fields.html.erb +3 -0
  34. data/app/views/alchemy/admin/ingredients/_text_fields.html.erb +3 -0
  35. data/app/views/alchemy/admin/ingredients/update.js.erb +7 -0
  36. data/app/views/alchemy/admin/languages/_form.html.erb +1 -1
  37. data/app/views/alchemy/admin/languages/_language.html.erb +1 -1
  38. data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +1 -1
  39. data/app/views/alchemy/admin/partials/_routes.html.erb +2 -1
  40. data/app/views/alchemy/ingredients/_headline_editor.html.erb +22 -20
  41. data/app/views/alchemy/ingredients/_headline_view.html.erb +1 -0
  42. data/app/views/alchemy/ingredients/_text_editor.html.erb +3 -0
  43. data/app/views/alchemy/ingredients/_text_view.html.erb +7 -3
  44. data/app/views/alchemy/ingredients/shared/_anchor.html.erb +9 -0
  45. data/app/views/alchemy/messages_mailer/contact_form_mail.de.text.erb +2 -0
  46. data/app/views/alchemy/messages_mailer/contact_form_mail.en.text.erb +2 -0
  47. data/app/views/alchemy/messages_mailer/contact_form_mail.es.text.erb +2 -0
  48. data/config/locales/alchemy.en.yml +5 -2
  49. data/config/routes.rb +1 -0
  50. data/lib/alchemy/error_tracking/error_logger.rb +13 -0
  51. data/lib/alchemy/error_tracking.rb +3 -1
  52. data/lib/alchemy/install/tasks.rb +1 -7
  53. data/lib/alchemy/page_layout.rb +0 -113
  54. data/lib/alchemy/test_support/shared_dom_ids_examples.rb +119 -0
  55. data/lib/alchemy/upgrader/tasks/add_page_versions.rb +2 -2
  56. data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +7 -5
  57. data/lib/alchemy/version.rb +1 -1
  58. data/lib/alchemy.rb +4 -0
  59. data/lib/alchemy_cms.rb +1 -1
  60. data/lib/generators/alchemy/elements/templates/view.html.erb +1 -1
  61. data/lib/generators/alchemy/elements/templates/view.html.haml +1 -1
  62. data/lib/generators/alchemy/elements/templates/view.html.slim +1 -1
  63. data/lib/tasks/alchemy/thumbnails.rake +1 -1
  64. data/package/admin.js +2 -0
  65. data/package/src/ingredient_anchor_link.js +17 -0
  66. data/package.json +2 -2
  67. data/vendor/assets/javascripts/tinymce/tinymce.min.js +2 -2
  68. metadata +32 -6
  69. data/lib/non_stupid_digest_assets.rb +0 -55
@@ -41,112 +41,8 @@ module Alchemy
41
41
  all.detect { |a| a["name"].casecmp(name).zero? }
42
42
  end
43
43
 
44
- def get_all_by_attributes(attributes)
45
- return [] if attributes.blank?
46
-
47
- if attributes.is_a? Hash
48
- layouts = []
49
- attributes.stringify_keys.each do |key, value|
50
- result = all.select { |l| l.key?(key) && l[key].to_s.casecmp(value.to_s).zero? }
51
- layouts += result unless result.empty?
52
- end
53
- layouts
54
- else
55
- []
56
- end
57
- end
58
-
59
- # Returns page layouts ready for Rails' select form helper.
60
- #
61
- def layouts_for_select(language_id, only_layoutpages = false)
62
- @map_array = []
63
- mapped_layouts_for_select(selectable_layouts(language_id, only_layoutpages))
64
- end
65
-
66
- # Returns all layouts that can be used for creating a new page.
67
- #
68
- # It removes all layouts from available layouts that are unique and already taken and that are marked as hide.
69
- #
70
- # @param [Fixnum]
71
- # language_id of current used Language.
72
- # @param [Boolean] (false)
73
- # Pass true to only select layouts for global/layout pages.
74
- #
75
- def selectable_layouts(language_id, only_layoutpages = false)
76
- @language_id = language_id
77
- all.select do |layout|
78
- if only_layoutpages
79
- layout["layoutpage"] && layout_available?(layout)
80
- else
81
- !layout["layoutpage"] && layout_available?(layout)
82
- end
83
- end
84
- end
85
-
86
- # Returns all names of elements defined in given page layout.
87
- #
88
- def element_names_for(page_layout)
89
- if definition = get(page_layout)
90
- definition.fetch("elements", [])
91
- else
92
- Rails.logger.warn "\n+++ Warning: No layout definition for #{page_layout} found! in page_layouts.yml\n"
93
- []
94
- end
95
- end
96
-
97
- # Translates name for given layout
98
- #
99
- # === Translation example
100
- #
101
- # en:
102
- # alchemy:
103
- # page_layout_names:
104
- # products_overview: Products Overview
105
- #
106
- # @param [String]
107
- # The layout name
108
- #
109
- def human_layout_name(layout)
110
- Alchemy.t(layout, scope: "page_layout_names", default: layout.to_s.humanize)
111
- end
112
-
113
44
  private
114
45
 
115
- # Returns true if the given layout is unique and not already taken or it should be hidden.
116
- #
117
- def layout_available?(layout)
118
- !layout["hide"] && !already_taken?(layout) && available_on_site?(layout)
119
- end
120
-
121
- # Returns true if this layout is unique and already taken by another page.
122
- #
123
- def already_taken?(layout)
124
- layout["unique"] && page_with_layout_existing?(layout["name"])
125
- end
126
-
127
- # Returns true if one page already has the given layout
128
- #
129
- def page_with_layout_existing?(layout)
130
- Alchemy::Page.where(page_layout: layout, language_id: @language_id).pluck(:id).any?
131
- end
132
-
133
- # Returns true if given layout is available for current site.
134
- #
135
- # If no site layouts are defined it always returns true.
136
- #
137
- # == Example
138
- #
139
- # # config/alchemy/site_layouts.yml
140
- # - name: default_site
141
- # page_layouts: [default_intro]
142
- #
143
- def available_on_site?(layout)
144
- return false unless Alchemy::Site.current
145
-
146
- Alchemy::Site.current.definition.blank? ||
147
- Alchemy::Site.current.definition.fetch("page_layouts", []).include?(layout["name"])
148
- end
149
-
150
46
  # Reads the layout definitions from +config/alchemy/page_layouts.yml+.
151
47
  #
152
48
  def read_definitions_file
@@ -168,15 +64,6 @@ module Alchemy
168
64
  def layouts_file_path
169
65
  Rails.root.join "config/alchemy/page_layouts.yml"
170
66
  end
171
-
172
- # Maps given layouts for Rails select form helper.
173
- #
174
- def mapped_layouts_for_select(layouts)
175
- layouts.each do |layout|
176
- @map_array << [human_layout_name(layout["name"]), layout["name"]]
177
- end
178
- @map_array
179
- end
180
67
  end
181
68
  end
182
69
  end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples_for "having dom ids" do
4
+ let(:element) { build(:alchemy_element, name: "element_with_ingredients") }
5
+
6
+ let(:ingredient) do
7
+ described_class.new(
8
+ element: element,
9
+ role: "headline",
10
+ )
11
+ end
12
+
13
+ describe "setting dom id from value" do
14
+ subject do
15
+ ingredient.valid? && ingredient.dom_id
16
+ end
17
+
18
+ before do
19
+ expect_any_instance_of(described_class).to receive(:settings).at_least(:once) { settings }
20
+ end
21
+
22
+ context "without anchor settings" do
23
+ let(:settings) do
24
+ {}
25
+ end
26
+
27
+ it "does not set a dom_id" do
28
+ is_expected.to be_nil
29
+ end
30
+ end
31
+
32
+ context "with anchor setting set to true" do
33
+ let(:settings) do
34
+ { anchor: true }
35
+ end
36
+
37
+ it "parameterizes dom_id" do
38
+ ingredient.dom_id = "SE Headline"
39
+ is_expected.to eq "se-headline"
40
+ end
41
+ end
42
+
43
+ context "with anchor setting set to from_value" do
44
+ let(:settings) do
45
+ { anchor: "from_value" }
46
+ end
47
+
48
+ context "with a value present" do
49
+ let(:ingredient) do
50
+ described_class.new(
51
+ element: element,
52
+ role: "headline",
53
+ value: "Hello World",
54
+ )
55
+ end
56
+
57
+ it "sets a dom_id from value" do
58
+ is_expected.to eq "hello-world"
59
+ end
60
+ end
61
+
62
+ context "with no value present" do
63
+ let(:ingredient) do
64
+ described_class.new(
65
+ element: element,
66
+ role: "headline",
67
+ value: "",
68
+ )
69
+ end
70
+
71
+ it "sets no dom_id" do
72
+ is_expected.to eq ""
73
+ end
74
+ end
75
+ end
76
+
77
+ context "with anchor setting set to fixed value" do
78
+ context "that is false" do
79
+ let(:settings) do
80
+ { anchor: false }
81
+ end
82
+
83
+ it "sets no dom_id" do
84
+ is_expected.to be_nil
85
+ end
86
+ end
87
+
88
+ context "that is true" do
89
+ let(:settings) do
90
+ { anchor: true }
91
+ end
92
+
93
+ it "sets no dom_id" do
94
+ is_expected.to be_nil
95
+ end
96
+ end
97
+
98
+ context "that is from_value" do
99
+ let(:settings) do
100
+ { anchor: true }
101
+ end
102
+
103
+ it "sets no dom_id" do
104
+ is_expected.to be_nil
105
+ end
106
+ end
107
+
108
+ context "that is a non reserved value" do
109
+ let(:settings) do
110
+ { anchor: "FixED VALUE" }
111
+ end
112
+
113
+ it "sets the dom_id to fixed value" do
114
+ is_expected.to eq "fixed-value"
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -15,10 +15,10 @@ module Alchemy::Upgrader::Tasks
15
15
  Alchemy::Page.transaction do
16
16
  page.versions.create!(
17
17
  public_on: page.legacy_public_on,
18
- public_until: page.legacy_public_until
18
+ public_until: page.legacy_public_until,
19
19
  ).tap do |version|
20
20
  # We must not use .find_each here to not mess up the order of elements
21
- page.draft_version.elements.not_nested.available.each do |element|
21
+ page.draft_version.elements.not_nested.published.each do |element|
22
22
  Alchemy::Element.copy(element, page_version_id: version.id)
23
23
  end
24
24
  end
@@ -7,7 +7,7 @@ module Alchemy::Upgrader::Tasks
7
7
  include Thor::Actions
8
8
 
9
9
  no_tasks do
10
- def create_ingredients
10
+ def create_ingredients(verbose: !Rails.env.test?)
11
11
  Alchemy::Deprecation.silence do
12
12
  elements_with_ingredients = Alchemy::ElementDefinition.all.select { |d| d.key?(:ingredients) }
13
13
  if ENV["ONLY"]
@@ -22,13 +22,13 @@ module Alchemy::Upgrader::Tasks
22
22
  elements_with_ingredients.map do |element_definition|
23
23
  elements = all_elements.select { |e| e.name == element_definition[:name] }
24
24
  if elements.any?
25
- puts "-- Creating ingredients for #{elements.count} #{element_definition[:name]}(s)"
25
+ puts "-- Creating ingredients for #{elements.count} #{element_definition[:name]}(s)" if verbose
26
26
  elements.each do |element|
27
27
  MigrateElementIngredients.call(element)
28
- print "."
28
+ print "." if verbose
29
29
  end
30
- puts "\n"
31
- else
30
+ puts "\n" if verbose
31
+ elsif verbose
32
32
  puts "-- No #{element_definition[:name]} elements found for migration."
33
33
  end
34
34
  end
@@ -56,6 +56,8 @@ module Alchemy::Upgrader::Tasks
56
56
  ingredient.value = content.ingredient
57
57
  end
58
58
  data = ingredient.class.stored_attributes.fetch(:data, []).each_with_object({}) do |attr, d|
59
+ next unless essence.respond_to?(attr)
60
+
59
61
  d[attr] = essence.public_send(attr)
60
62
  end
61
63
  ingredient.data = data
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "6.0.14"
4
+ VERSION = "6.1.0"
5
5
 
6
6
  def self.version
7
7
  VERSION
data/lib/alchemy.rb CHANGED
@@ -57,6 +57,10 @@ module Alchemy
57
57
  @_preview_sources ||= Set.new << Alchemy::Admin::PreviewUrl
58
58
  end
59
59
 
60
+ def self.preview_sources=(sources)
61
+ @_preview_sources = Array(sources)
62
+ end
63
+
60
64
  # Define page publish targets
61
65
  #
62
66
  # A publish target is a ActiveJob that gets performed
data/lib/alchemy_cms.rb CHANGED
@@ -15,7 +15,7 @@ require "handlebars_assets"
15
15
  require "jquery-rails"
16
16
  require "jquery-ui-rails"
17
17
  require "kaminari"
18
- require "non_stupid_digest_assets"
18
+ require "non-stupid-digest-assets"
19
19
  require "ransack"
20
20
  require "request_store"
21
21
  require "responders"
@@ -19,7 +19,7 @@
19
19
  <%- end -%>
20
20
  <%- end -%>
21
21
  <%- if @element['nestable_elements'].present? -%>
22
- <%%= render <%= @element_name %>.nested_elements.available %>
22
+ <%%= render <%= @element_name %>.nested_elements.published %>
23
23
  <%- end -%>
24
24
  <%%- end -%>
25
25
  <%%- end -%>
@@ -18,5 +18,5 @@
18
18
  <%- end -%>
19
19
  <%- end -%>
20
20
  <%- if @element['nestable_elements'].present? -%>
21
- = render <%= @element_name -%>.nested_elements.available
21
+ = render <%= @element_name -%>.nested_elements.published
22
22
  <%- end -%>
@@ -18,5 +18,5 @@
18
18
  <%- end -%>
19
19
  <%- end -%>
20
20
  <%- if @element['nestable_elements'].present? -%>
21
- = render <%= @element_name -%>.nested_elements.available
21
+ = render <%= @element_name -%>.nested_elements.published
22
22
  <%- end -%>
@@ -46,7 +46,7 @@ namespace :alchemy do
46
46
  ingredient_pictures = Alchemy::Ingredients::Picture.
47
47
  joins(:element).
48
48
  preload({ related_object: :thumbs }).
49
- merge(Alchemy::Element.available)
49
+ merge(Alchemy::Element.published)
50
50
 
51
51
  if ENV["ELEMENTS"].present?
52
52
  ingredient_pictures = ingredient_pictures.merge(
data/package/admin.js CHANGED
@@ -2,6 +2,7 @@ import translate from "./src/i18n"
2
2
  import translationData from "./src/translations"
3
3
  import NodeTree from "./src/node_tree"
4
4
  import fileEditors from "./src/file_editors"
5
+ import IngredientAnchorLink from "./src/ingredient_anchor_link"
5
6
  import pictureEditors from "./src/picture_editors"
6
7
  import ImageLoader from "./src/image_loader"
7
8
  import ImageCropper from "./src/image_cropper"
@@ -24,6 +25,7 @@ Object.assign(Alchemy, {
24
25
  pictureEditors,
25
26
  ImageLoader: ImageLoader.init,
26
27
  ImageCropper,
28
+ IngredientAnchorLink,
27
29
  Datepicker,
28
30
  Sitemap,
29
31
  PagePublicationFields
@@ -0,0 +1,17 @@
1
+ export default class IngredientAnchorLink {
2
+ static updateIcon(ingredientId, active = false) {
3
+ const ingredientEditor = document.querySelector(
4
+ `[data-ingredient-id="${ingredientId}"]`
5
+ )
6
+ if (ingredientEditor) {
7
+ const icon = ingredientEditor.querySelector(
8
+ ".edit-ingredient-anchor-link > a > .icon"
9
+ )
10
+ if (icon) {
11
+ active
12
+ ? icon.classList.replace("far", "fas")
13
+ : icon.classList.replace("fas", "far")
14
+ }
15
+ }
16
+ }
17
+ }
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alchemy_cms/admin",
3
- "version": "6.0.14",
3
+ "version": "6.1.0",
4
4
  "description": "AlchemyCMS",
5
5
  "browser": "package/admin.js",
6
6
  "files": [
@@ -31,7 +31,7 @@
31
31
  "devDependencies": {
32
32
  "@babel/core": "^7.9.6",
33
33
  "@babel/preset-env": "^7.9.6",
34
- "babel-jest": "^27.0.1",
34
+ "babel-jest": "^29.0.1",
35
35
  "jest": "^25.2.7",
36
36
  "prettier": "^2.0.2",
37
37
  "xhr-mock": "^2.5.1"