alchemy_cms 6.0.0.b1 → 6.0.0.b2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/alchemy_cms.gemspec +1 -1
- data/app/assets/stylesheets/alchemy/archive.scss +14 -0
- data/app/controllers/alchemy/admin/attachments_controller.rb +3 -3
- data/app/controllers/alchemy/admin/pages_controller.rb +1 -9
- data/app/controllers/alchemy/admin/pictures_controller.rb +21 -8
- data/app/controllers/alchemy/admin/resources_controller.rb +84 -10
- data/app/controllers/alchemy/api/elements_controller.rb +12 -8
- data/app/controllers/alchemy/api/pages_controller.rb +4 -2
- data/app/models/alchemy/attachment.rb +24 -7
- data/app/models/alchemy/element/presenters.rb +18 -1
- data/app/models/alchemy/ingredient.rb +5 -0
- data/app/models/alchemy/page.rb +10 -1
- data/app/models/alchemy/page/page_scopes.rb +4 -0
- data/app/models/alchemy/picture.rb +14 -38
- data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +1 -1
- data/app/views/alchemy/admin/attachments/index.html.erb +2 -3
- data/app/views/alchemy/admin/pages/_toolbar.html.erb +1 -1
- data/app/views/alchemy/admin/pages/index.html.erb +2 -9
- data/app/views/alchemy/admin/partials/_search_form.html.erb +9 -0
- data/app/views/alchemy/admin/pictures/_archive.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +4 -2
- data/app/views/alchemy/admin/pictures/index.html.erb +8 -3
- data/app/views/alchemy/admin/resources/_filter.html.erb +12 -0
- data/app/views/alchemy/admin/resources/_filter_bar.html.erb +14 -17
- data/app/views/alchemy/admin/resources/_form.html.erb +2 -0
- data/app/views/alchemy/admin/resources/_table_header.html.erb +15 -0
- data/app/views/alchemy/admin/resources/index.html.erb +3 -11
- data/config/locales/alchemy.en.yml +85 -49
- data/lib/alchemy/forms/builder.rb +21 -1
- data/lib/alchemy/resource_filter.rb +40 -0
- data/lib/alchemy/resources_helper.rb +1 -16
- data/lib/alchemy/test_support/shared_ingredient_examples.rb +21 -3
- data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +14 -6
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy_cms.rb +1 -0
- data/lib/generators/alchemy/menus/templates/node.html.erb +1 -1
- data/lib/generators/alchemy/menus/templates/node.html.haml +1 -1
- data/lib/generators/alchemy/menus/templates/node.html.slim +1 -1
- data/lib/generators/alchemy/menus/templates/wrapper.html.erb +1 -1
- data/lib/generators/alchemy/menus/templates/wrapper.html.haml +1 -1
- data/lib/generators/alchemy/menus/templates/wrapper.html.slim +1 -1
- data/package.json +1 -1
- metadata +10 -9
- data/app/views/alchemy/admin/attachments/_filter_bar.html.erb +0 -29
- data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +0 -30
|
@@ -18,11 +18,31 @@ module Alchemy
|
|
|
18
18
|
super
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
# Renders a simple_form input that displays a datepicker
|
|
22
|
+
#
|
|
23
|
+
def datepicker(attribute_name, options = {})
|
|
24
|
+
options[:wrapper] = :alchemy
|
|
25
|
+
|
|
26
|
+
type = options[:as] || :date
|
|
27
|
+
value = options.fetch(:input_html, {}).delete(:value)
|
|
28
|
+
date = value || object.send(attribute_name.to_sym).presence
|
|
29
|
+
date = Time.zone.parse(date) if date.is_a?(String)
|
|
30
|
+
|
|
31
|
+
input_options = {
|
|
32
|
+
type: :text,
|
|
33
|
+
class: type,
|
|
34
|
+
data: { datepicker_type: type },
|
|
35
|
+
value: date&.iso8601,
|
|
36
|
+
}.merge(options[:input_html] || {})
|
|
37
|
+
|
|
38
|
+
input attribute_name, as: :string, input_html: input_options
|
|
39
|
+
end
|
|
40
|
+
|
|
21
41
|
# Renders a button tag wrapped in a div with 'submit' class.
|
|
22
42
|
#
|
|
23
43
|
def submit(label, options = {})
|
|
24
44
|
options = {
|
|
25
|
-
wrapper_html: {class: "submit"},
|
|
45
|
+
wrapper_html: { class: "submit" },
|
|
26
46
|
}.update(options)
|
|
27
47
|
template.content_tag("div", options.delete(:wrapper_html)) do
|
|
28
48
|
template.content_tag("button", label, options.delete(:input_html))
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Alchemy
|
|
4
|
+
class ResourceFilter
|
|
5
|
+
attr_reader :name
|
|
6
|
+
|
|
7
|
+
def initialize(filter, resource_name)
|
|
8
|
+
@filter = filter
|
|
9
|
+
@name = filter[:name]
|
|
10
|
+
@resource_name = resource_name
|
|
11
|
+
@values = filter[:values].presence || []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def options_for_select
|
|
15
|
+
translated_values.zip(values)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def values
|
|
19
|
+
if translated?
|
|
20
|
+
@values.map { |v| v[1] }
|
|
21
|
+
else
|
|
22
|
+
@values
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def translated?
|
|
29
|
+
@values.first.is_a?(Array)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def translated_values
|
|
33
|
+
if translated?
|
|
34
|
+
@values.map { |a| a[0] }
|
|
35
|
+
else
|
|
36
|
+
@values.map { |v| Alchemy.t(v.to_sym, scope: ["filters", @resource_name, @name, "values"]) }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -107,12 +107,10 @@ module Alchemy
|
|
|
107
107
|
when "boolean"
|
|
108
108
|
options
|
|
109
109
|
when "date", "time", "datetime"
|
|
110
|
-
date = resource_instance_variable.send(attribute[:name]) || Time.current
|
|
111
110
|
options.merge(
|
|
112
111
|
as: "string",
|
|
113
112
|
input_html: {
|
|
114
|
-
|
|
115
|
-
value: date ? date.iso8601 : nil,
|
|
113
|
+
data: { datepicker_type: input_type },
|
|
116
114
|
},
|
|
117
115
|
)
|
|
118
116
|
when "text"
|
|
@@ -171,18 +169,5 @@ module Alchemy
|
|
|
171
169
|
def resource_has_tags
|
|
172
170
|
resource_model.respond_to?(:tag_counts) && resource_model.tag_counts.any?
|
|
173
171
|
end
|
|
174
|
-
|
|
175
|
-
def resource_has_filters
|
|
176
|
-
resource_model.respond_to?(:alchemy_resource_filters)
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def resource_filter_select
|
|
180
|
-
resource_model.alchemy_resource_filters.map do |filter_scope|
|
|
181
|
-
[
|
|
182
|
-
Alchemy.t(filter_scope.to_sym, scope: ["resources", resource_name, "filters"]),
|
|
183
|
-
filter_scope,
|
|
184
|
-
]
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
172
|
end
|
|
188
173
|
end
|
|
@@ -28,6 +28,16 @@ RSpec.shared_examples_for "an alchemy ingredient" do
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
context "with element" do
|
|
31
|
+
before do
|
|
32
|
+
expect(element).to receive(:ingredient_definition_for) do
|
|
33
|
+
{
|
|
34
|
+
settings: {
|
|
35
|
+
linkable: true,
|
|
36
|
+
},
|
|
37
|
+
}.with_indifferent_access
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
31
41
|
it { is_expected.to eq({ linkable: true }.with_indifferent_access) }
|
|
32
42
|
end
|
|
33
43
|
end
|
|
@@ -42,15 +52,23 @@ RSpec.shared_examples_for "an alchemy ingredient" do
|
|
|
42
52
|
end
|
|
43
53
|
|
|
44
54
|
context "with element" do
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
let(:definition) do
|
|
56
|
+
{
|
|
47
57
|
role: "headline",
|
|
48
58
|
type: "Text",
|
|
49
59
|
default: "Hello World",
|
|
50
60
|
settings: {
|
|
51
61
|
linkable: true,
|
|
52
62
|
},
|
|
53
|
-
}.with_indifferent_access
|
|
63
|
+
}.with_indifferent_access
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
before do
|
|
67
|
+
expect(element).to receive(:ingredient_definition_for) { definition }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "returns ingredient definition" do
|
|
71
|
+
is_expected.to eq(definition)
|
|
54
72
|
end
|
|
55
73
|
end
|
|
56
74
|
end
|
|
@@ -10,6 +10,9 @@ module Alchemy::Upgrader::Tasks
|
|
|
10
10
|
def create_ingredients
|
|
11
11
|
Alchemy::Deprecation.silence do
|
|
12
12
|
elements_with_ingredients = Alchemy::ElementDefinition.all.select { |d| d.key?(:ingredients) }
|
|
13
|
+
if ENV["ONLY"]
|
|
14
|
+
elements_with_ingredients = elements_with_ingredients.select { |d| d[:name].in? ENV["ONLY"].split(",") }
|
|
15
|
+
end
|
|
13
16
|
# eager load all elements that have ingredients defined but no ingredient records yet.
|
|
14
17
|
all_elements = Alchemy::Element
|
|
15
18
|
.named(elements_with_ingredients.map { |d| d[:name] })
|
|
@@ -22,21 +25,26 @@ module Alchemy::Upgrader::Tasks
|
|
|
22
25
|
puts "-- Creating ingredients for #{elements.count} #{element_definition[:name]}(s)"
|
|
23
26
|
elements.each do |element|
|
|
24
27
|
Alchemy::Element.transaction do
|
|
25
|
-
|
|
28
|
+
element_definition[:ingredients].each do |ingredient_definition|
|
|
26
29
|
content = element.content_by_name(ingredient_definition[:role])
|
|
27
30
|
next unless content
|
|
28
31
|
|
|
32
|
+
essence = content.essence
|
|
29
33
|
ingredient = Alchemy::Ingredient.build(role: ingredient_definition[:role], element: element)
|
|
30
|
-
belongs_to_associations =
|
|
34
|
+
belongs_to_associations = essence.class.reflect_on_all_associations(:belongs_to)
|
|
31
35
|
if belongs_to_associations.any?
|
|
32
|
-
ingredient.related_object =
|
|
36
|
+
ingredient.related_object = essence.public_send(belongs_to_associations.first.name)
|
|
33
37
|
else
|
|
34
38
|
ingredient.value = content.ingredient
|
|
35
39
|
end
|
|
36
|
-
|
|
40
|
+
data = ingredient.class.stored_attributes.fetch(:data, []).each_with_object({}) do |attr, d|
|
|
41
|
+
d[attr] = essence.public_send(attr)
|
|
42
|
+
end
|
|
43
|
+
ingredient.data = data
|
|
37
44
|
print "."
|
|
38
|
-
ingredient
|
|
39
|
-
|
|
45
|
+
ingredient.save!
|
|
46
|
+
content.destroy!
|
|
47
|
+
end
|
|
40
48
|
end
|
|
41
49
|
end
|
|
42
50
|
puts "\n"
|
data/lib/alchemy/version.rb
CHANGED
data/lib/alchemy_cms.rb
CHANGED
|
@@ -54,6 +54,7 @@ require_relative "alchemy/permissions"
|
|
|
54
54
|
require_relative "alchemy/resource"
|
|
55
55
|
require_relative "alchemy/tinymce"
|
|
56
56
|
require_relative "alchemy/taggable"
|
|
57
|
+
require_relative "alchemy/version"
|
|
57
58
|
|
|
58
59
|
# Require hacks
|
|
59
60
|
require_relative "kaminari/scoped_pagination_url_helper"
|
data/package.json
CHANGED
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.
|
|
4
|
+
version: 6.0.0.b2
|
|
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-
|
|
16
|
+
date: 2021-08-05 00:00:00.000000000 Z
|
|
17
17
|
dependencies:
|
|
18
18
|
- !ruby/object:Gem::Dependency
|
|
19
19
|
name: actionmailer
|
|
@@ -689,14 +689,14 @@ dependencies:
|
|
|
689
689
|
requirements:
|
|
690
690
|
- - "~>"
|
|
691
691
|
- !ruby/object:Gem::Version
|
|
692
|
-
version: '
|
|
692
|
+
version: '5.0'
|
|
693
693
|
type: :development
|
|
694
694
|
prerelease: false
|
|
695
695
|
version_requirements: !ruby/object:Gem::Requirement
|
|
696
696
|
requirements:
|
|
697
697
|
- - "~>"
|
|
698
698
|
- !ruby/object:Gem::Version
|
|
699
|
-
version: '
|
|
699
|
+
version: '5.0'
|
|
700
700
|
- !ruby/object:Gem::Dependency
|
|
701
701
|
name: timecop
|
|
702
702
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -1013,7 +1013,6 @@ files:
|
|
|
1013
1013
|
- app/views/alchemy/admin/attachments/_attachment.html.erb
|
|
1014
1014
|
- app/views/alchemy/admin/attachments/_file_to_assign.html.erb
|
|
1015
1015
|
- app/views/alchemy/admin/attachments/_files_list.html.erb
|
|
1016
|
-
- app/views/alchemy/admin/attachments/_filter_bar.html.erb
|
|
1017
1016
|
- app/views/alchemy/admin/attachments/_overlay_file_list.html.erb
|
|
1018
1017
|
- app/views/alchemy/admin/attachments/_replace_button.html.erb
|
|
1019
1018
|
- app/views/alchemy/admin/attachments/_tag_list.html.erb
|
|
@@ -1131,7 +1130,6 @@ files:
|
|
|
1131
1130
|
- app/views/alchemy/admin/pictures/_archive.html.erb
|
|
1132
1131
|
- app/views/alchemy/admin/pictures/_archive_overlay.html.erb
|
|
1133
1132
|
- app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb
|
|
1134
|
-
- app/views/alchemy/admin/pictures/_filter_bar.html.erb
|
|
1135
1133
|
- app/views/alchemy/admin/pictures/_form.html.erb
|
|
1136
1134
|
- app/views/alchemy/admin/pictures/_infos.html.erb
|
|
1137
1135
|
- app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb
|
|
@@ -1145,6 +1143,7 @@ files:
|
|
|
1145
1143
|
- app/views/alchemy/admin/pictures/index.js.erb
|
|
1146
1144
|
- app/views/alchemy/admin/pictures/show.html.erb
|
|
1147
1145
|
- app/views/alchemy/admin/pictures/update.js.erb
|
|
1146
|
+
- app/views/alchemy/admin/resources/_filter.html.erb
|
|
1148
1147
|
- app/views/alchemy/admin/resources/_filter_bar.html.erb
|
|
1149
1148
|
- app/views/alchemy/admin/resources/_form.html.erb
|
|
1150
1149
|
- app/views/alchemy/admin/resources/_per_page_select.html.erb
|
|
@@ -1323,6 +1322,7 @@ files:
|
|
|
1323
1322
|
- lib/alchemy/paths.rb
|
|
1324
1323
|
- lib/alchemy/permissions.rb
|
|
1325
1324
|
- lib/alchemy/resource.rb
|
|
1325
|
+
- lib/alchemy/resource_filter.rb
|
|
1326
1326
|
- lib/alchemy/resources_helper.rb
|
|
1327
1327
|
- lib/alchemy/routing_constraints.rb
|
|
1328
1328
|
- lib/alchemy/seeder.rb
|
|
@@ -1516,8 +1516,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
1516
1516
|
version: 1.3.1
|
|
1517
1517
|
requirements:
|
|
1518
1518
|
- ImageMagick (libmagick), v6.6 or greater.
|
|
1519
|
-
rubygems_version: 3.1.
|
|
1520
|
-
signing_key:
|
|
1519
|
+
rubygems_version: 3.1.6
|
|
1520
|
+
signing_key:
|
|
1521
1521
|
specification_version: 4
|
|
1522
1522
|
summary: A powerful, userfriendly and flexible CMS for Rails
|
|
1523
1523
|
test_files: []
|
|
1524
|
+
...
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
<div id="filter_bar">
|
|
2
|
-
<h3><%= Alchemy.t('Filter') %></h3>
|
|
3
|
-
<%= select_tag(
|
|
4
|
-
'file_type_filter',
|
|
5
|
-
options_for_select(
|
|
6
|
-
Alchemy::Attachment.file_types_for_select,
|
|
7
|
-
search_filter_params[:file_type]
|
|
8
|
-
),
|
|
9
|
-
include_blank: Alchemy.t('Show all files'),
|
|
10
|
-
data: { remote: !!request.xhr? },
|
|
11
|
-
class: 'alchemy_selectbox'
|
|
12
|
-
) %>
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
<script type="text/javascript">
|
|
16
|
-
$(function() {
|
|
17
|
-
$('#file_type_filter').on('change', function(e) {
|
|
18
|
-
var $this = $(this);
|
|
19
|
-
var url = '<%= alchemy.admin_attachments_path(search_filter_params.except(:file_type).to_h) %>';
|
|
20
|
-
if ($this.data('remote') === true) {
|
|
21
|
-
$.get(url, {file_type: $this.val()}, null, 'script');
|
|
22
|
-
} else {
|
|
23
|
-
delimiter = url.match(/\?/) ? '&' : '?';
|
|
24
|
-
Turbolinks.visit(url + delimiter + 'file_type=' + encodeURIComponent($this.val()));
|
|
25
|
-
}
|
|
26
|
-
return false;
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
</script>
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
<div id="filter_bar">
|
|
2
|
-
<h3><%= Alchemy.t('Filter') %></h3>
|
|
3
|
-
<%= select_tag(
|
|
4
|
-
'picture_filter',
|
|
5
|
-
options_for_select([
|
|
6
|
-
[Alchemy.t(:all_pictures), ''],
|
|
7
|
-
[Alchemy.t(:last_upload_only), 'last_upload'],
|
|
8
|
-
[Alchemy.t(:recently_uploaded_only), 'recent'],
|
|
9
|
-
[Alchemy.t(:without_tag), 'without_tag']
|
|
10
|
-
], search_filter_params[:filter]),
|
|
11
|
-
:data => { :remote => !!request.xhr? },
|
|
12
|
-
:class => 'alchemy_selectbox'
|
|
13
|
-
) %>
|
|
14
|
-
</div>
|
|
15
|
-
|
|
16
|
-
<script type="text/javascript">
|
|
17
|
-
$(function() {
|
|
18
|
-
$('#picture_filter').on('change', function(e) {
|
|
19
|
-
var $this = $(this);
|
|
20
|
-
var url = '<%= alchemy.admin_pictures_path(search_filter_params.except(:filter).to_h) %>';
|
|
21
|
-
if ($this.data('remote') === true) {
|
|
22
|
-
$.get(url, {filter: $this.val()}, null, 'script');
|
|
23
|
-
} else {
|
|
24
|
-
delimiter = url.match(/\?/) ? '&' : '?';
|
|
25
|
-
Turbolinks.visit(url + delimiter + 'filter=' + $this.val());
|
|
26
|
-
}
|
|
27
|
-
return false;
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
</script>
|