alchemy_cms 6.1.10 → 7.0.0.pre.a
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/.github/workflows/ci.yml +0 -3
- data/.gitignore +1 -6
- data/CHANGELOG.md +19 -44
- data/Gemfile +1 -1
- data/Rakefile +14 -9
- data/alchemy_cms.gemspec +2 -3
- data/app/assets/javascripts/alchemy/alchemy.dirty.js.coffee +1 -1
- data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +18 -32
- data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +2 -2
- data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +2 -2
- data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +27 -29
- data/app/assets/stylesheets/alchemy/elements.scss +16 -35
- data/app/assets/stylesheets/alchemy/forms.scss +0 -4
- data/app/assets/stylesheets/alchemy/node-select.scss +2 -2
- data/app/controllers/alchemy/admin/attachments_controller.rb +0 -1
- data/app/controllers/alchemy/admin/elements_controller.rb +7 -32
- data/app/controllers/alchemy/admin/pages_controller.rb +1 -1
- data/app/controllers/alchemy/admin/pictures_controller.rb +1 -1
- data/app/controllers/alchemy/admin/resources_controller.rb +1 -18
- data/app/controllers/alchemy/api/elements_controller.rb +0 -2
- data/app/controllers/alchemy/api/pages_controller.rb +8 -4
- data/app/controllers/alchemy/messages_controller.rb +9 -9
- data/app/controllers/alchemy/pages_controller.rb +23 -18
- data/app/decorators/alchemy/element_editor.rb +10 -30
- data/app/helpers/alchemy/admin/elements_helper.rb +0 -2
- data/app/helpers/alchemy/elements_block_helper.rb +5 -42
- data/app/helpers/alchemy/elements_helper.rb +3 -11
- data/app/helpers/alchemy/pages_helper.rb +0 -4
- data/app/models/alchemy/attachment.rb +6 -3
- data/app/models/alchemy/base_record.rb +2 -0
- data/app/models/alchemy/eager_loading.rb +0 -1
- data/app/models/alchemy/element/element_ingredients.rb +1 -8
- data/app/models/alchemy/element/presenters.rb +9 -25
- data/app/models/alchemy/element.rb +2 -18
- data/app/models/alchemy/ingredient.rb +17 -6
- data/app/models/alchemy/ingredients/audio.rb +2 -0
- data/app/models/alchemy/ingredients/datetime.rb +3 -1
- data/app/models/alchemy/ingredients/file.rb +7 -0
- data/app/models/alchemy/ingredients/headline.rb +6 -0
- data/app/models/alchemy/ingredients/link.rb +2 -0
- data/app/models/alchemy/ingredients/node.rb +2 -0
- data/app/models/alchemy/ingredients/page.rb +2 -0
- data/app/models/alchemy/ingredients/picture.rb +11 -0
- data/app/models/alchemy/ingredients/richtext.rb +6 -0
- data/app/models/alchemy/ingredients/select.rb +1 -0
- data/app/models/alchemy/ingredients/text.rb +8 -0
- data/app/models/alchemy/ingredients/video.rb +2 -0
- data/app/models/alchemy/node.rb +9 -6
- data/app/models/alchemy/page/page_elements.rb +5 -26
- data/app/models/alchemy/page/page_layouts.rb +0 -14
- data/app/models/alchemy/page/page_natures.rb +0 -10
- data/app/models/alchemy/page.rb +0 -10
- data/app/models/alchemy/picture/transformations.rb +0 -30
- data/app/models/alchemy/picture/url.rb +1 -1
- data/app/models/alchemy/picture.rb +14 -13
- data/app/models/alchemy/picture_thumb/create.rb +7 -18
- data/app/models/alchemy/picture_thumb/file_store.rb +33 -0
- data/app/models/alchemy/picture_thumb.rb +10 -10
- data/app/models/concerns/alchemy/picture_thumbnails.rb +2 -6
- data/app/serializers/alchemy/element_serializer.rb +1 -6
- data/app/services/alchemy/delete_elements.rb +1 -7
- data/app/services/alchemy/duplicate_element.rb +1 -6
- data/app/views/alchemy/admin/elements/_element.html.erb +5 -22
- data/app/views/alchemy/admin/elements/create.js.erb +1 -1
- data/app/views/alchemy/admin/elements/fold.js.erb +2 -2
- data/app/views/alchemy/admin/elements/order.js.erb +1 -1
- data/app/views/alchemy/admin/elements/update.js.erb +1 -2
- data/app/views/alchemy/admin/pages/_external_link.html.erb +2 -2
- data/app/views/alchemy/admin/pages/_file_link.html.erb +2 -2
- data/app/views/alchemy/admin/pages/_internal_link.html.erb +2 -2
- data/app/views/alchemy/admin/pages/_table.html.erb +0 -6
- data/app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb +3 -6
- data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -3
- data/app/views/alchemy/admin/pictures/_infos.html.erb +4 -6
- data/app/views/alchemy/admin/resources/_per_page_select.html.erb +1 -1
- data/app/views/alchemy/ingredients/_boolean_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/_headline_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/_html_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/_node_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/_picture_editor.html.erb +4 -4
- data/app/views/alchemy/ingredients/_select_editor.html.erb +2 -2
- data/app/views/alchemy/ingredients/_text_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +3 -3
- data/app/views/alchemy/pages/_meta_data.html.erb +0 -1
- data/app/views/layouts/alchemy/admin.html.erb +5 -1
- data/config/alchemy/config.yml +6 -6
- data/config/brakeman.ignore +56 -57
- data/config/locales/alchemy.en.yml +99 -113
- data/config/routes.rb +1 -16
- data/db/migrate/20230121212637_alchemy_six_point_one.rb +248 -0
- data/lib/alchemy/cache_digests/template_tracker.rb +6 -7
- data/lib/alchemy/config.rb +2 -2
- data/lib/alchemy/deprecation.rb +1 -1
- data/lib/alchemy/errors.rb +0 -11
- data/lib/alchemy/hints.rb +10 -10
- data/lib/alchemy/permissions.rb +4 -17
- data/lib/alchemy/routing_constraints.rb +3 -3
- data/lib/alchemy/searchable_resource.rb +38 -0
- data/lib/alchemy/seeder.rb +2 -8
- data/lib/alchemy/tasks/tidy.rb +0 -38
- data/lib/alchemy/test_support/capybara_helpers.rb +69 -0
- data/lib/alchemy/test_support/factories/element_factory.rb +0 -6
- data/lib/alchemy/test_support/factories/ingredient_factory.rb +1 -1
- data/lib/alchemy/test_support/factories/page_factory.rb +4 -2
- data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +0 -20
- data/lib/alchemy/test_support/shared_dom_ids_examples.rb +1 -1
- data/lib/alchemy/test_support/shared_ingredient_examples.rb +1 -1
- data/lib/alchemy/tinymce.rb +1 -18
- data/lib/alchemy/upgrader/seven_point_zero.rb +45 -0
- data/lib/alchemy/upgrader/tasks/.keep +0 -0
- data/lib/alchemy/upgrader.rb +8 -3
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy.rb +0 -19
- data/lib/alchemy_cms.rb +1 -2
- data/lib/generators/alchemy/elements/elements_generator.rb +0 -1
- data/lib/generators/alchemy/elements/templates/view.html.erb +1 -10
- data/lib/generators/alchemy/elements/templates/view.html.haml +1 -9
- data/lib/generators/alchemy/elements/templates/view.html.slim +1 -9
- data/lib/generators/alchemy/install/files/alchemy.en.yml +7 -8
- data/lib/generators/alchemy/install/files/application.html.erb +1 -1
- data/lib/generators/alchemy/install/install_generator.rb +18 -34
- data/lib/generators/alchemy/install/templates/elements.yml.tt +12 -12
- data/lib/non_stupid_digest_assets.rb +1 -1
- data/lib/tasks/alchemy/thumbnails.rake +2 -21
- data/lib/tasks/alchemy/tidy.rake +1 -12
- data/lib/tasks/alchemy/upgrade.rake +10 -47
- data/package/dist/admin.js +16 -0
- data/package/dist/admin.js.map +7 -0
- data/package.json +5 -3
- metadata +18 -147
- data/app/controllers/alchemy/admin/contents_controller.rb +0 -21
- data/app/controllers/alchemy/admin/essence_audios_controller.rb +0 -30
- data/app/controllers/alchemy/admin/essence_files_controller.rb +0 -31
- data/app/controllers/alchemy/admin/essence_pictures_controller.rb +0 -43
- data/app/controllers/alchemy/admin/essence_videos_controller.rb +0 -34
- data/app/controllers/alchemy/api/contents_controller.rb +0 -52
- data/app/decorators/alchemy/content_editor.rb +0 -119
- data/app/helpers/alchemy/admin/contents_helper.rb +0 -42
- data/app/helpers/alchemy/admin/essences_helper.rb +0 -31
- data/app/models/alchemy/content/factory.rb +0 -143
- data/app/models/alchemy/content.rb +0 -247
- data/app/models/alchemy/element/element_contents.rb +0 -200
- data/app/models/alchemy/element/element_essences.rb +0 -133
- data/app/models/alchemy/essence_audio.rb +0 -13
- data/app/models/alchemy/essence_boolean.rb +0 -20
- data/app/models/alchemy/essence_date.rb +0 -25
- data/app/models/alchemy/essence_file.rb +0 -49
- data/app/models/alchemy/essence_headline.rb +0 -41
- data/app/models/alchemy/essence_html.rb +0 -23
- data/app/models/alchemy/essence_link.rb +0 -21
- data/app/models/alchemy/essence_node.rb +0 -19
- data/app/models/alchemy/essence_page.rb +0 -17
- data/app/models/alchemy/essence_picture.rb +0 -67
- data/app/models/alchemy/essence_picture_view.rb +0 -90
- data/app/models/alchemy/essence_richtext.rb +0 -44
- data/app/models/alchemy/essence_select.rb +0 -19
- data/app/models/alchemy/essence_text.rb +0 -23
- data/app/models/alchemy/essence_video.rb +0 -13
- data/app/serializers/alchemy/content_serializer.rb +0 -17
- data/app/serializers/alchemy/essence_boolean_serializer.rb +0 -10
- data/app/serializers/alchemy/essence_date_serializer.rb +0 -10
- data/app/serializers/alchemy/essence_file_serializer.rb +0 -13
- data/app/serializers/alchemy/essence_html_serializer.rb +0 -10
- data/app/serializers/alchemy/essence_link_serializer.rb +0 -13
- data/app/serializers/alchemy/essence_picture_serializer.rb +0 -28
- data/app/serializers/alchemy/essence_richtext_serializer.rb +0 -11
- data/app/serializers/alchemy/essence_select_serializer.rb +0 -10
- data/app/serializers/alchemy/essence_text_serializer.rb +0 -22
- data/app/views/alchemy/admin/contents/create.js.erb +0 -21
- data/app/views/alchemy/admin/essence_audios/edit.html.erb +0 -7
- data/app/views/alchemy/admin/essence_files/edit.html.erb +0 -21
- data/app/views/alchemy/admin/essence_pictures/destroy.js.erb +0 -5
- data/app/views/alchemy/admin/essence_pictures/edit.html.erb +0 -30
- data/app/views/alchemy/admin/essence_pictures/save_link.js.erb +0 -3
- data/app/views/alchemy/admin/essence_pictures/update.js.erb +0 -8
- data/app/views/alchemy/admin/essence_videos/edit.html.erb +0 -12
- data/app/views/alchemy/essences/_essence_audio_editor.html.erb +0 -4
- data/app/views/alchemy/essences/_essence_audio_view.html.erb +0 -15
- data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +0 -11
- data/app/views/alchemy/essences/_essence_boolean_view.html.erb +0 -2
- data/app/views/alchemy/essences/_essence_date_editor.html.erb +0 -16
- data/app/views/alchemy/essences/_essence_date_view.html.erb +0 -10
- data/app/views/alchemy/essences/_essence_file_editor.html.erb +0 -54
- data/app/views/alchemy/essences/_essence_file_view.html.erb +0 -18
- data/app/views/alchemy/essences/_essence_headline_editor.html.erb +0 -36
- data/app/views/alchemy/essences/_essence_headline_view.html.erb +0 -10
- data/app/views/alchemy/essences/_essence_html_editor.html.erb +0 -10
- data/app/views/alchemy/essences/_essence_html_view.html.erb +0 -2
- data/app/views/alchemy/essences/_essence_link_editor.html.erb +0 -30
- data/app/views/alchemy/essences/_essence_link_view.html.erb +0 -10
- data/app/views/alchemy/essences/_essence_node_editor.html.erb +0 -27
- data/app/views/alchemy/essences/_essence_node_view.html.erb +0 -1
- data/app/views/alchemy/essences/_essence_page_editor.html.erb +0 -26
- data/app/views/alchemy/essences/_essence_page_view.html.erb +0 -5
- data/app/views/alchemy/essences/_essence_picture_editor.html.erb +0 -59
- data/app/views/alchemy/essences/_essence_picture_view.html.erb +0 -6
- data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +0 -14
- data/app/views/alchemy/essences/_essence_richtext_view.html.erb +0 -4
- data/app/views/alchemy/essences/_essence_select_editor.html.erb +0 -28
- data/app/views/alchemy/essences/_essence_select_view.html.erb +0 -2
- data/app/views/alchemy/essences/_essence_text_editor.html.erb +0 -29
- data/app/views/alchemy/essences/_essence_text_view.html.erb +0 -17
- data/app/views/alchemy/essences/_essence_video_editor.html.erb +0 -4
- data/app/views/alchemy/essences/_essence_video_view.html.erb +0 -19
- data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +0 -59
- data/app/views/alchemy/essences/shared/_linkable_essence_tools.html.erb +0 -20
- data/app/views/alchemy/pages/show.rss.builder +0 -21
- data/db/migrate/20200226213334_alchemy_four_point_four.rb +0 -313
- data/db/migrate/20200423073425_create_alchemy_essence_nodes.rb +0 -11
- data/db/migrate/20200504210159_remove_site_id_from_nodes.rb +0 -28
- data/db/migrate/20200505215518_add_language_id_foreign_key_to_alchemy_pages.rb +0 -8
- data/db/migrate/20200511113603_add_menu_type_to_alchemy_nodes.rb +0 -27
- data/db/migrate/20200514091507_make_page_layoutpage_null_false.rb +0 -6
- data/db/migrate/20200519073500_remove_visible_from_alchemy_pages.rb +0 -24
- data/db/migrate/20200617110713_create_alchemy_picture_thumbs.rb +0 -22
- data/db/migrate/20200907111332_remove_tri_state_booleans.rb +0 -33
- data/db/migrate/20201207131309_create_page_versions.rb +0 -19
- data/db/migrate/20201207135820_add_page_version_id_to_alchemy_elements.rb +0 -76
- data/db/migrate/20210205143548_rename_public_on_and_public_until_on_alchemy_pages.rb +0 -10
- data/db/migrate/20210326105046_add_sanitized_body_to_alchemy_essence_richtexts.rb +0 -7
- data/db/migrate/20210406093436_add_alchemy_essence_headlines.rb +0 -12
- data/db/migrate/20210506135919_create_essence_audios.rb +0 -19
- data/db/migrate/20210506140258_create_essence_videos.rb +0 -23
- data/db/migrate/20210508091432_create_alchemy_ingredients.rb +0 -22
- data/db/migrate/20220514072456_restrict_on_delete_page_id_foreign_key_from_alchemy_nodes.rb +0 -13
- data/db/migrate/20220622130905_add_playsinline_to_alchemy_essence_videos.rb +0 -9
- data/lib/alchemy/essence.rb +0 -250
- data/lib/alchemy/tasks/usage.rb +0 -34
- data/lib/alchemy/test_support/essence_shared_examples.rb +0 -271
- data/lib/alchemy/test_support/factories/content_factory.rb +0 -20
- data/lib/alchemy/test_support/factories/essence_audio_factory.rb +0 -7
- data/lib/alchemy/test_support/factories/essence_file_factory.rb +0 -7
- data/lib/alchemy/test_support/factories/essence_page_factory.rb +0 -7
- data/lib/alchemy/test_support/factories/essence_picture_factory.rb +0 -11
- data/lib/alchemy/test_support/factories/essence_text_factory.rb +0 -7
- data/lib/alchemy/test_support/factories/essence_video_factory.rb +0 -7
- data/lib/alchemy/upgrader/five_point_zero.rb +0 -41
- data/lib/alchemy/upgrader/six_point_zero.rb +0 -21
- data/lib/alchemy/upgrader/tasks/add_page_versions.rb +0 -33
- data/lib/alchemy/upgrader/tasks/element_views_updater.rb +0 -34
- data/lib/alchemy/upgrader/tasks/harden_gutentag_migrations.rb +0 -29
- data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +0 -73
- data/lib/generators/alchemy/essence/essence_generator.rb +0 -49
- data/lib/generators/alchemy/essence/templates/editor.html.erb +0 -17
- data/lib/generators/alchemy/essence/templates/view.html.erb +0 -2
- data/lib/generators/alchemy/install/files/babel.config.js +0 -64
- data/lib/tasks/alchemy/usage.rake +0 -44
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Alchemy
|
|
4
|
-
class ContentEditor < SimpleDelegator
|
|
5
|
-
alias_method :content, :__getobj__
|
|
6
|
-
|
|
7
|
-
def to_partial_path
|
|
8
|
-
"alchemy/essences/#{essence_partial_name}_editor"
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def css_classes
|
|
12
|
-
[
|
|
13
|
-
"content_editor",
|
|
14
|
-
essence_partial_name,
|
|
15
|
-
deprecated? ? "deprecated" : nil,
|
|
16
|
-
].compact
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def data_attributes
|
|
20
|
-
{
|
|
21
|
-
content_id: id,
|
|
22
|
-
content_name: name,
|
|
23
|
-
}
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Returns a string to be passed to Rails form field tags to ensure we have same params layout everywhere.
|
|
27
|
-
#
|
|
28
|
-
# === Example:
|
|
29
|
-
#
|
|
30
|
-
# <%= text_field_tag content_editor.form_field_name, content_editor.ingredient %>
|
|
31
|
-
#
|
|
32
|
-
# === Options:
|
|
33
|
-
#
|
|
34
|
-
# You can pass an Essence column_name. Default is 'ingredient'
|
|
35
|
-
#
|
|
36
|
-
# ==== Example:
|
|
37
|
-
#
|
|
38
|
-
# <%= text_field_tag content_editor.form_field_name(:link), content_editor.ingredient %>
|
|
39
|
-
#
|
|
40
|
-
def form_field_name(essence_column = "ingredient")
|
|
41
|
-
"contents[#{id}][#{essence_column}]"
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def form_field_id(essence_column = "ingredient")
|
|
45
|
-
"contents_#{id}_#{essence_column}"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Fixes Rails partial renderer calling to_model on the object
|
|
49
|
-
# which reveals the delegated content instead of this decorator.
|
|
50
|
-
def respond_to?(method_name)
|
|
51
|
-
return false if method_name == :to_model
|
|
52
|
-
|
|
53
|
-
super
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def has_warnings?
|
|
57
|
-
definition.blank? || deprecated?
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def warnings
|
|
61
|
-
return unless has_warnings?
|
|
62
|
-
|
|
63
|
-
if definition.blank?
|
|
64
|
-
Logger.warn("Content #{name} is missing its definition", caller(1..1))
|
|
65
|
-
Alchemy.t(:content_definition_missing)
|
|
66
|
-
else
|
|
67
|
-
deprecation_notice
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Returns a deprecation notice for contents marked deprecated
|
|
72
|
-
#
|
|
73
|
-
# You can either use localizations or pass a String as notice
|
|
74
|
-
# in the content definition.
|
|
75
|
-
#
|
|
76
|
-
# == Custom deprecation notices
|
|
77
|
-
#
|
|
78
|
-
# Use general content deprecation notice
|
|
79
|
-
#
|
|
80
|
-
# - name: element_name
|
|
81
|
-
# contents:
|
|
82
|
-
# - name: old_content
|
|
83
|
-
# type: EssenceText
|
|
84
|
-
# deprecated: true
|
|
85
|
-
#
|
|
86
|
-
# Add a translation to your locale file for a per content notice.
|
|
87
|
-
#
|
|
88
|
-
# en:
|
|
89
|
-
# alchemy:
|
|
90
|
-
# content_deprecation_notices:
|
|
91
|
-
# element_name:
|
|
92
|
-
# old_content: Foo baz widget is deprecated
|
|
93
|
-
#
|
|
94
|
-
# or use the global translation that apply to all deprecated contents.
|
|
95
|
-
#
|
|
96
|
-
# en:
|
|
97
|
-
# alchemy:
|
|
98
|
-
# content_deprecation_notice: Foo baz widget is deprecated
|
|
99
|
-
#
|
|
100
|
-
# or pass string as deprecation notice.
|
|
101
|
-
#
|
|
102
|
-
# - name: element_name
|
|
103
|
-
# contents:
|
|
104
|
-
# - name: old_content
|
|
105
|
-
# type: EssenceText
|
|
106
|
-
# deprecated: This content will be removed soon.
|
|
107
|
-
#
|
|
108
|
-
def deprecation_notice
|
|
109
|
-
case definition["deprecated"]
|
|
110
|
-
when String
|
|
111
|
-
definition["deprecated"]
|
|
112
|
-
when TrueClass
|
|
113
|
-
Alchemy.t(name,
|
|
114
|
-
scope: [:content_deprecation_notices, element.name],
|
|
115
|
-
default: Alchemy.t(:content_deprecated))
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Alchemy
|
|
4
|
-
module Admin
|
|
5
|
-
module ContentsHelper
|
|
6
|
-
include Alchemy::Admin::BaseHelper
|
|
7
|
-
|
|
8
|
-
# Renders the name of elements content.
|
|
9
|
-
#
|
|
10
|
-
# Displays a warning icon if content is missing its definition.
|
|
11
|
-
#
|
|
12
|
-
# Displays a mandatory field indicator, if the content has validations.
|
|
13
|
-
#
|
|
14
|
-
def render_content_name(content)
|
|
15
|
-
if content.blank?
|
|
16
|
-
warning("Content is nil")
|
|
17
|
-
return
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
content_name = content.name_for_label
|
|
21
|
-
|
|
22
|
-
if content.has_warnings?
|
|
23
|
-
icon = hint_with_tooltip(content.warnings)
|
|
24
|
-
content_name = "#{icon} #{content_name}".html_safe
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
if content.has_validations?
|
|
28
|
-
"#{content_name}<span class='validation_indicator'>*</span>".html_safe
|
|
29
|
-
else
|
|
30
|
-
content_name
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Renders the label and a remove link for a content.
|
|
35
|
-
def content_label(content)
|
|
36
|
-
content_tag :label, for: content.form_field_id do
|
|
37
|
-
[render_content_name(content), render_hint_for(content)].compact.join(" ").html_safe
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Alchemy
|
|
4
|
-
module Admin
|
|
5
|
-
module EssencesHelper
|
|
6
|
-
# Renders a thumbnail for given EssencePicture content with correct cropping and size
|
|
7
|
-
def essence_picture_thumbnail(content)
|
|
8
|
-
picture = content.ingredient
|
|
9
|
-
essence = content.essence
|
|
10
|
-
|
|
11
|
-
return if picture.nil?
|
|
12
|
-
|
|
13
|
-
image_tag(
|
|
14
|
-
essence.thumbnail_url,
|
|
15
|
-
alt: picture.name,
|
|
16
|
-
class: "img_paddingtop",
|
|
17
|
-
title: Alchemy.t(:image_name, name: picture.name),
|
|
18
|
-
)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Size value for edit picture dialog
|
|
22
|
-
def edit_picture_dialog_size(content)
|
|
23
|
-
if content.settings[:caption_as_textarea]
|
|
24
|
-
content.settings[:sizes] ? "380x320" : "380x300"
|
|
25
|
-
else
|
|
26
|
-
content.settings[:sizes] ? "380x290" : "380x255"
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Alchemy
|
|
4
|
-
# Holds everything concerning the building and creating of contents and the related essence object.
|
|
5
|
-
#
|
|
6
|
-
class Content < BaseRecord
|
|
7
|
-
module Factory
|
|
8
|
-
extend ActiveSupport::Concern
|
|
9
|
-
|
|
10
|
-
module ClassMethods
|
|
11
|
-
SKIPPED_ATTRIBUTES_ON_COPY = %w(position created_at updated_at creator_id updater_id element_id id)
|
|
12
|
-
|
|
13
|
-
# Builds a new content as descriped in the elements.yml file.
|
|
14
|
-
#
|
|
15
|
-
# @param [Hash]
|
|
16
|
-
# The content definition used for finding the content in +elements.yml+ file
|
|
17
|
-
#
|
|
18
|
-
def new(attributes = {})
|
|
19
|
-
element = attributes[:element] || Element.find_by(id: attributes[:element_id])
|
|
20
|
-
return super if attributes.empty? || element.nil?
|
|
21
|
-
|
|
22
|
-
definition = element.content_definition_for(attributes[:name])
|
|
23
|
-
if definition.blank? && attributes[:essence_type].nil?
|
|
24
|
-
raise ContentDefinitionError, "No definition found in elements.yml for #{attributes.inspect} and #{element.inspect}"
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
super(
|
|
28
|
-
name: attributes[:name],
|
|
29
|
-
essence_type: attributes[:essence_type] || normalize_essence_type(definition[:type]),
|
|
30
|
-
element: element,
|
|
31
|
-
).tap(&:build_essence)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Creates a new content from elements definition in the +elements.yml+ file.
|
|
35
|
-
#
|
|
36
|
-
# 1. It builds the content
|
|
37
|
-
# 2. It creates the essence record (content object gets saved)
|
|
38
|
-
#
|
|
39
|
-
# @return [Alchemy::Content]
|
|
40
|
-
#
|
|
41
|
-
def create(attributes = {})
|
|
42
|
-
new(attributes).tap do |content|
|
|
43
|
-
content.essence.save && content.save
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Creates a copy of source and also copies the associated essence.
|
|
48
|
-
#
|
|
49
|
-
# You can pass a differences hash to update the attributes of the copy.
|
|
50
|
-
#
|
|
51
|
-
# === Example
|
|
52
|
-
#
|
|
53
|
-
# @copy = Alchemy::Content.copy(@content, {element_id: 3})
|
|
54
|
-
# @copy.element_id # => 3
|
|
55
|
-
#
|
|
56
|
-
def copy(source, differences = {})
|
|
57
|
-
Content.new(
|
|
58
|
-
source.attributes.with_indifferent_access.
|
|
59
|
-
except(*SKIPPED_ATTRIBUTES_ON_COPY).
|
|
60
|
-
merge(differences.with_indifferent_access)
|
|
61
|
-
).tap do |new_content|
|
|
62
|
-
new_content.build_essence(
|
|
63
|
-
source.essence.attributes.
|
|
64
|
-
except(*SKIPPED_ATTRIBUTES_ON_COPY)
|
|
65
|
-
)
|
|
66
|
-
new_content.save
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Returns all content definitions from elements.yml
|
|
71
|
-
#
|
|
72
|
-
def definitions
|
|
73
|
-
definitions = Element.definitions.flat_map { |e| e["contents"] }
|
|
74
|
-
definitions.compact!
|
|
75
|
-
definitions
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Returns a normalized Essence type
|
|
79
|
-
#
|
|
80
|
-
# Adds Alchemy module name in front of given essence type
|
|
81
|
-
# unless there is a Class with the specified name that is an essence.
|
|
82
|
-
#
|
|
83
|
-
# @param [String]
|
|
84
|
-
# the essence type to normalize
|
|
85
|
-
#
|
|
86
|
-
def normalize_essence_type(essence_type)
|
|
87
|
-
essence_type = essence_type.classify
|
|
88
|
-
return essence_type if is_an_essence?(essence_type)
|
|
89
|
-
|
|
90
|
-
"Alchemy::#{essence_type}"
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
private
|
|
94
|
-
|
|
95
|
-
def is_an_essence?(essence_type)
|
|
96
|
-
klass = Module.const_get(essence_type)
|
|
97
|
-
klass.is_a?(Class) && klass.new.acts_as_essence?
|
|
98
|
-
rescue NameError
|
|
99
|
-
false
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Instance Methods
|
|
104
|
-
|
|
105
|
-
# Returns the definition hash from +elements.yml+ file.
|
|
106
|
-
#
|
|
107
|
-
def definition
|
|
108
|
-
if element.blank?
|
|
109
|
-
log_warning "Content with id #{id} is missing its Element."
|
|
110
|
-
return {}
|
|
111
|
-
end
|
|
112
|
-
element.content_definition_for(name) || {}
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Build essence from definition.
|
|
116
|
-
#
|
|
117
|
-
# If an optional type is passed, this type of essence gets created.
|
|
118
|
-
#
|
|
119
|
-
def build_essence(attributes = {})
|
|
120
|
-
self.essence = essence_class.new(
|
|
121
|
-
{ content: self, ingredient: default_value }.merge(attributes)
|
|
122
|
-
)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# Creates essence from definition.
|
|
126
|
-
#
|
|
127
|
-
# If an optional type is passed, this type of essence gets created.
|
|
128
|
-
#
|
|
129
|
-
def create_essence!(attrs = {})
|
|
130
|
-
build_essence(attrs).save!
|
|
131
|
-
save!
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
private
|
|
135
|
-
|
|
136
|
-
# Returns a class constant from definition's type field or the essence_type column
|
|
137
|
-
#
|
|
138
|
-
def essence_class
|
|
139
|
-
(essence_type || Content.normalize_essence_type(definition["type"])).constantize
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
end
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# == Schema Information
|
|
4
|
-
#
|
|
5
|
-
# Table name: alchemy_contents
|
|
6
|
-
#
|
|
7
|
-
# id :integer not null, primary key
|
|
8
|
-
# name :string
|
|
9
|
-
# essence_type :string not null
|
|
10
|
-
# essence_id :integer not null
|
|
11
|
-
# element_id :integer not null
|
|
12
|
-
# position :integer
|
|
13
|
-
# created_at :datetime not null
|
|
14
|
-
# updated_at :datetime not null
|
|
15
|
-
# creator_id :integer
|
|
16
|
-
# updater_id :integer
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
require_dependency "alchemy/content/factory"
|
|
20
|
-
|
|
21
|
-
module Alchemy
|
|
22
|
-
# @deprecated
|
|
23
|
-
class Content < BaseRecord
|
|
24
|
-
include Alchemy::Logger
|
|
25
|
-
include Alchemy::Hints
|
|
26
|
-
|
|
27
|
-
# Concerns
|
|
28
|
-
include Factory
|
|
29
|
-
|
|
30
|
-
belongs_to :essence, polymorphic: true, dependent: :destroy, inverse_of: :content
|
|
31
|
-
belongs_to :element, touch: true, inverse_of: :contents
|
|
32
|
-
has_one :page, through: :element
|
|
33
|
-
|
|
34
|
-
# Essence scopes
|
|
35
|
-
scope :essence_booleans, -> { where(essence_type: "Alchemy::EssenceBoolean") }
|
|
36
|
-
scope :essence_dates, -> { where(essence_type: "Alchemy::EssenceDate") }
|
|
37
|
-
scope :essence_files, -> { where(essence_type: "Alchemy::EssenceFile") }
|
|
38
|
-
scope :essence_htmls, -> { where(essence_type: "Alchemy::EssenceHtml") }
|
|
39
|
-
scope :essence_links, -> { where(essence_type: "Alchemy::EssenceLink") }
|
|
40
|
-
scope :essence_pictures, -> { where(essence_type: "Alchemy::EssencePicture") }
|
|
41
|
-
scope :essence_richtexts, -> { where(essence_type: "Alchemy::EssenceRichtext") }
|
|
42
|
-
scope :essence_selects, -> { where(essence_type: "Alchemy::EssenceSelect") }
|
|
43
|
-
scope :essence_texts, -> { where(essence_type: "Alchemy::EssenceText") }
|
|
44
|
-
scope :named, ->(name) { where(name: name) }
|
|
45
|
-
scope :available, -> { published }
|
|
46
|
-
scope :published, -> { joins(:element).merge(Element.published) }
|
|
47
|
-
scope :not_restricted, -> { joins(:element).merge(Element.not_restricted) }
|
|
48
|
-
|
|
49
|
-
delegate :restricted?, to: :page, allow_nil: true
|
|
50
|
-
delegate :public?, to: :element, allow_nil: true
|
|
51
|
-
|
|
52
|
-
class << self
|
|
53
|
-
# Returns the translated label for a content name.
|
|
54
|
-
#
|
|
55
|
-
# Translate it in your locale yml file:
|
|
56
|
-
#
|
|
57
|
-
# alchemy:
|
|
58
|
-
# content_names:
|
|
59
|
-
# foo: Bar
|
|
60
|
-
#
|
|
61
|
-
# Optionally you can scope your content name to an element:
|
|
62
|
-
#
|
|
63
|
-
# alchemy:
|
|
64
|
-
# content_names:
|
|
65
|
-
# article:
|
|
66
|
-
# foo: Baz
|
|
67
|
-
#
|
|
68
|
-
def translated_label_for(content_name, element_name = nil)
|
|
69
|
-
Alchemy.t(
|
|
70
|
-
content_name,
|
|
71
|
-
scope: "content_names.#{element_name}",
|
|
72
|
-
default: Alchemy.t("content_names.#{content_name}", default: content_name.humanize),
|
|
73
|
-
)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# The content's view partial is dependent from its name
|
|
78
|
-
#
|
|
79
|
-
# == Define contents
|
|
80
|
-
#
|
|
81
|
-
# Contents are defined in the +config/alchemy/elements.yml+ file
|
|
82
|
-
#
|
|
83
|
-
# - name: article
|
|
84
|
-
# contents:
|
|
85
|
-
# - name: headline
|
|
86
|
-
# type: EssenceText
|
|
87
|
-
#
|
|
88
|
-
# == Override the view
|
|
89
|
-
#
|
|
90
|
-
# Content partials live in +app/views/alchemy/essences+
|
|
91
|
-
#
|
|
92
|
-
def to_partial_path
|
|
93
|
-
"alchemy/essences/#{essence_partial_name}_view"
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Settings from the elements.yml definition
|
|
97
|
-
def settings
|
|
98
|
-
return {} if definition.blank?
|
|
99
|
-
|
|
100
|
-
@settings ||= definition.fetch(:settings, {})
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Fetches value from settings
|
|
104
|
-
#
|
|
105
|
-
# @param key [Symbol] - The hash key you want to fetch the value from
|
|
106
|
-
# @param options [Hash] - An optional Hash that can override the settings.
|
|
107
|
-
# Normally passed as options hash into the content
|
|
108
|
-
# editor view.
|
|
109
|
-
def settings_value(key, options = {})
|
|
110
|
-
settings.update(options || {}).symbolize_keys[key.to_sym]
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def siblings
|
|
114
|
-
return [] if !element
|
|
115
|
-
|
|
116
|
-
element.contents
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Gets the ingredient from essence
|
|
120
|
-
def ingredient
|
|
121
|
-
return nil if essence.nil?
|
|
122
|
-
|
|
123
|
-
essence.ingredient
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Serialized object representation for json api
|
|
127
|
-
#
|
|
128
|
-
def serialize
|
|
129
|
-
{
|
|
130
|
-
name: name,
|
|
131
|
-
value: serialized_ingredient,
|
|
132
|
-
link: essence.try(:link),
|
|
133
|
-
}.delete_if { |_k, v| v.blank? }
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Ingredient value from essence for json api
|
|
137
|
-
#
|
|
138
|
-
# If the essence responds to +serialized_ingredient+ method it takes this
|
|
139
|
-
# otherwise it uses the ingredient column.
|
|
140
|
-
#
|
|
141
|
-
def serialized_ingredient
|
|
142
|
-
essence.try(:serialized_ingredient) || ingredient
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# Sets the ingredient from essence
|
|
146
|
-
def ingredient=(value)
|
|
147
|
-
raise EssenceMissingError if essence.nil?
|
|
148
|
-
|
|
149
|
-
essence.ingredient = value
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
# Updates the essence.
|
|
153
|
-
#
|
|
154
|
-
# Called from +Alchemy::Element#update_contents+
|
|
155
|
-
#
|
|
156
|
-
# Adds errors to self.base if essence validation fails.
|
|
157
|
-
#
|
|
158
|
-
def update_essence(params = {})
|
|
159
|
-
raise EssenceMissingError if essence.nil?
|
|
160
|
-
|
|
161
|
-
if essence.update(params)
|
|
162
|
-
true
|
|
163
|
-
else
|
|
164
|
-
errors.add(:essence, :validation_failed)
|
|
165
|
-
false
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def essence_validation_failed?
|
|
170
|
-
essence.errors.any?
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def has_validations?
|
|
174
|
-
definition["validate"].present?
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
# Returns a string used as dom id on html elements.
|
|
178
|
-
def dom_id
|
|
179
|
-
return "" if essence.nil?
|
|
180
|
-
|
|
181
|
-
"#{essence_partial_name}_#{id}"
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
# Returns the translated name for displaying in labels, etc.
|
|
185
|
-
def name_for_label
|
|
186
|
-
self.class.translated_label_for(name, element.name)
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def linked?
|
|
190
|
-
essence && !essence.link.blank?
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
def deprecated?
|
|
194
|
-
!!definition["deprecated"]
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
# Returns true if this content should be taken for element preview.
|
|
198
|
-
def preview_content?
|
|
199
|
-
!!definition["as_element_title"]
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
# Proxy method that returns the preview text from essence.
|
|
203
|
-
#
|
|
204
|
-
def preview_text(maxlength = 30)
|
|
205
|
-
essence.preview_text(maxlength)
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def essence_partial_name
|
|
209
|
-
return "" if essence.nil?
|
|
210
|
-
|
|
211
|
-
essence.partial_name
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def normalized_essence_type
|
|
215
|
-
self.class.normalize_essence_type(essence_type)
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
# Returns true if there is a tinymce setting defined on the content definiton
|
|
219
|
-
# or if the +essence.has_tinymce?+ returns true.
|
|
220
|
-
def has_tinymce?
|
|
221
|
-
settings[:tinymce].present? || (essence.present? && essence.has_tinymce?)
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
# Returns true if there is a tinymce setting defined that contains settings.
|
|
225
|
-
def has_custom_tinymce_config?
|
|
226
|
-
settings[:tinymce].is_a?(Hash)
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
# Returns css class names for the content textarea.
|
|
230
|
-
def tinymce_class_name
|
|
231
|
-
"has_tinymce" + (has_custom_tinymce_config? ? " #{element.name}_#{name}" : "")
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
# Returns the default value from content definition
|
|
235
|
-
#
|
|
236
|
-
# If the value is a symbol it gets passed through i18n
|
|
237
|
-
# inside the +alchemy.default_content_texts+ scope
|
|
238
|
-
def default_value(default = definition[:default])
|
|
239
|
-
case default
|
|
240
|
-
when Symbol
|
|
241
|
-
Alchemy.t(default, scope: :default_content_texts)
|
|
242
|
-
else
|
|
243
|
-
default
|
|
244
|
-
end
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
end
|