alchemy_cms 7.0.0.pre.a → 7.0.0.pre.c
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/brakeman-analysis.yml +2 -2
- data/.github/workflows/lint.yml +37 -0
- data/.github/workflows/{ci.yml → test.yml} +8 -8
- data/.gitignore +0 -5
- data/.hound.yml +2 -3
- data/.rubocop.yml +4 -350
- data/.standard.yml +3 -0
- data/CHANGELOG.md +33 -0
- data/Gemfile +3 -2
- data/README.md +10 -12
- data/Rakefile +0 -19
- data/alchemy_cms.gemspec +4 -2
- data/app/assets/config/alchemy_manifest.js +1 -0
- data/app/assets/javascripts/alchemy/admin.js +0 -2
- data/app/assets/javascripts/alchemy/alchemy.dirty.js.coffee +1 -1
- data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +5 -12
- data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +6 -1
- data/app/assets/stylesheets/alchemy/base.scss +2 -2
- data/app/components/alchemy/ingredients/audio_view.rb +37 -0
- data/app/components/alchemy/ingredients/base_view.rb +38 -0
- data/app/components/alchemy/ingredients/boolean_view.rb +13 -0
- data/app/components/alchemy/ingredients/datetime_view.rb +22 -0
- data/app/components/alchemy/ingredients/file_view.rb +40 -0
- data/app/components/alchemy/ingredients/headline_view.rb +20 -0
- data/app/components/alchemy/ingredients/html_view.rb +9 -0
- data/app/components/alchemy/ingredients/link_view.rb +25 -0
- data/app/components/alchemy/ingredients/node_view.rb +11 -0
- data/app/components/alchemy/ingredients/page_view.rb +15 -0
- data/app/components/alchemy/ingredients/picture_view.rb +108 -0
- data/app/components/alchemy/ingredients/richtext_view.rb +22 -0
- data/app/components/alchemy/ingredients/select_view.rb +6 -0
- data/app/components/alchemy/ingredients/text_view.rb +41 -0
- data/app/components/alchemy/ingredients/video_view.rb +39 -0
- data/app/controllers/alchemy/admin/attachments_controller.rb +3 -3
- data/app/controllers/alchemy/admin/base_controller.rb +7 -7
- data/app/controllers/alchemy/admin/clipboard_controller.rb +2 -2
- data/app/controllers/alchemy/admin/elements_controller.rb +26 -11
- data/app/controllers/alchemy/admin/languages_controller.rb +1 -1
- data/app/controllers/alchemy/admin/nodes_controller.rb +2 -2
- data/app/controllers/alchemy/admin/pages_controller.rb +10 -10
- data/app/controllers/alchemy/admin/pictures_controller.rb +14 -14
- data/app/controllers/alchemy/admin/resources_controller.rb +27 -28
- data/app/controllers/alchemy/admin/styleguide_controller.rb +1 -0
- data/app/controllers/alchemy/admin/tags_controller.rb +11 -11
- data/app/controllers/alchemy/api/base_controller.rb +2 -2
- data/app/controllers/alchemy/api/elements_controller.rb +11 -11
- data/app/controllers/alchemy/api/ingredients_controller.rb +1 -1
- data/app/controllers/alchemy/api/nodes_controller.rb +1 -1
- data/app/controllers/alchemy/api/pages_controller.rb +11 -11
- data/app/controllers/alchemy/attachments_controller.rb +3 -3
- data/app/controllers/alchemy/base_controller.rb +1 -8
- data/app/controllers/alchemy/messages_controller.rb +9 -9
- data/app/controllers/alchemy/pages_controller.rb +8 -19
- data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +1 -0
- data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +5 -7
- data/app/controllers/concerns/alchemy/legacy_page_redirects.rb +5 -5
- data/app/decorators/alchemy/element_editor.rb +4 -4
- data/app/decorators/alchemy/ingredient_editor.rb +6 -6
- data/app/helpers/alchemy/admin/attachments_helper.rb +1 -1
- data/app/helpers/alchemy/admin/base_helper.rb +21 -22
- data/app/helpers/alchemy/admin/elements_helper.rb +1 -1
- data/app/helpers/alchemy/admin/form_helper.rb +1 -1
- data/app/helpers/alchemy/admin/navigation_helper.rb +7 -7
- data/app/helpers/alchemy/admin/pages_helper.rb +2 -2
- data/app/helpers/alchemy/admin/tags_helper.rb +3 -3
- data/app/helpers/alchemy/base_helper.rb +2 -2
- data/app/helpers/alchemy/elements_block_helper.rb +9 -7
- data/app/helpers/alchemy/elements_helper.rb +12 -12
- data/app/helpers/alchemy/pages_helper.rb +11 -11
- data/app/helpers/alchemy/url_helper.rb +1 -1
- data/{package/src → app/javascript/alchemy_admin}/datepicker.js +1 -0
- data/{package/src → app/javascript/alchemy_admin}/node_tree.js +2 -2
- data/{package/src → app/javascript/alchemy_admin}/page_publication_fields.js +1 -1
- data/{package/src → app/javascript/alchemy_admin}/page_sorter.js +1 -1
- data/{package/src → app/javascript/alchemy_admin}/picture_editors.js +2 -2
- data/{package/src → app/javascript/alchemy_admin}/sitemap.js +4 -4
- data/app/javascript/alchemy_admin/tinymce.js +142 -0
- data/app/javascript/alchemy_admin.js +34 -0
- data/app/mailers/alchemy/messages_mailer.rb +1 -1
- data/app/models/alchemy/attachment.rb +6 -6
- data/app/models/alchemy/base_record.rb +1 -0
- data/app/models/alchemy/eager_loading.rb +6 -6
- data/app/models/alchemy/element/definitions.rb +1 -1
- data/app/models/alchemy/element/element_ingredients.rb +3 -3
- data/app/models/alchemy/element.rb +2 -2
- data/app/models/alchemy/elements_repository.rb +1 -1
- data/app/models/alchemy/image_cropper_settings.rb +2 -2
- data/app/models/alchemy/ingredient.rb +14 -12
- data/app/models/alchemy/ingredient_validator.rb +1 -1
- data/app/models/alchemy/ingredients/datetime.rb +1 -1
- data/app/models/alchemy/ingredients/file.rb +5 -5
- data/app/models/alchemy/ingredients/headline.rb +4 -4
- data/app/models/alchemy/ingredients/picture.rb +27 -9
- data/app/models/alchemy/ingredients/richtext.rb +15 -12
- data/app/models/alchemy/ingredients/text.rb +6 -6
- data/app/models/alchemy/language/code.rb +1 -1
- data/app/models/alchemy/language.rb +4 -4
- data/app/models/alchemy/legacy_page_url.rb +1 -1
- data/app/models/alchemy/node.rb +2 -2
- data/app/models/alchemy/page/page_elements.rb +14 -14
- data/app/models/alchemy/page/page_naming.rb +4 -4
- data/app/models/alchemy/page/page_natures.rb +1 -1
- data/app/models/alchemy/page/page_scopes.rb +5 -5
- data/app/models/alchemy/page.rb +11 -11
- data/app/models/alchemy/picture/calculations.rb +2 -2
- data/app/models/alchemy/picture/transformations.rb +2 -2
- data/app/models/alchemy/picture/url.rb +4 -4
- data/app/models/alchemy/picture.rb +11 -10
- data/app/models/alchemy/picture_thumb/create.rb +1 -1
- data/app/models/alchemy/picture_thumb.rb +1 -1
- data/app/models/alchemy/picture_variant.rb +2 -3
- data/app/models/alchemy/tag.rb +8 -0
- data/app/models/concerns/alchemy/picture_thumbnails.rb +6 -6
- data/app/serializers/alchemy/base_serializer.rb +1 -1
- data/app/serializers/alchemy/page_tree_serializer.rb +7 -7
- data/app/services/alchemy/duplicate_element.rb +3 -3
- data/app/services/alchemy/tag_validations.rb +1 -1
- data/app/views/alchemy/_menubar.html.erb +1 -1
- data/app/views/alchemy/admin/attachments/_replace_button.html.erb +1 -1
- data/app/views/alchemy/admin/attachments/destroy.js.erb +1 -1
- data/app/views/alchemy/admin/elements/_element.html.erb +3 -0
- data/app/views/alchemy/admin/nodes/index.html.erb +4 -2
- data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +1 -1
- data/app/views/alchemy/admin/pages/edit.html.erb +3 -7
- data/app/views/alchemy/admin/pages/index.html.erb +1 -1
- data/app/views/alchemy/admin/pages/update.js.erb +12 -6
- data/app/views/alchemy/admin/pictures/_infos.html.erb +1 -1
- data/app/views/alchemy/admin/resources/_filter_bar.html.erb +1 -1
- data/app/views/alchemy/admin/styleguide/index.html.erb +1 -1
- data/app/views/alchemy/admin/uploader/_button.html.erb +1 -1
- data/app/views/alchemy/base/permission_denied.js.erb +1 -1
- data/app/views/alchemy/base/redirect.js.erb +1 -1
- data/app/views/alchemy/ingredients/_audio_view.html.erb +1 -14
- data/app/views/alchemy/ingredients/_boolean_view.html.erb +1 -1
- data/app/views/alchemy/ingredients/_datetime_view.html.erb +3 -9
- data/app/views/alchemy/ingredients/_file_view.html.erb +3 -16
- data/app/views/alchemy/ingredients/_headline_view.html.erb +4 -10
- data/app/views/alchemy/ingredients/_html_view.html.erb +1 -1
- data/app/views/alchemy/ingredients/_link_view.html.erb +4 -9
- data/app/views/alchemy/ingredients/_node_view.html.erb +1 -1
- data/app/views/alchemy/ingredients/_page_view.html.erb +1 -4
- data/app/views/alchemy/ingredients/_picture_view.html.erb +4 -5
- data/app/views/alchemy/ingredients/_richtext_editor.html.erb +11 -2
- data/app/views/alchemy/ingredients/_richtext_view.html.erb +3 -3
- data/app/views/alchemy/ingredients/_select_view.html.erb +1 -1
- data/app/views/alchemy/ingredients/_text_view.html.erb +3 -19
- data/app/views/alchemy/ingredients/_video_view.html.erb +3 -18
- data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +1 -0
- data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +1 -0
- data/app/views/layouts/alchemy/admin.html.erb +9 -15
- data/bin/importmap +4 -0
- data/bin/setup +28 -0
- data/bin/start +17 -0
- data/config/brakeman.ignore +0 -46
- data/config/importmap.rb +8 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/dragonfly.rb +1 -0
- data/config/initializers/mime_types.rb +1 -0
- data/config/initializers/mini_profiler.rb +1 -0
- data/config/initializers/simple_form.rb +3 -2
- data/config/locales/alchemy.en.yml +1 -1
- data/config/routes.rb +21 -20
- data/config/spring.rb +1 -0
- data/db/migrate/20230121212637_alchemy_six_point_one.rb +8 -8
- data/db/migrate/20230505132743_add_indexes_to_alchemy_pictures.rb +6 -0
- data/lib/alchemy/admin/locale.rb +3 -3
- data/lib/alchemy/admin/preview_url.rb +2 -2
- data/lib/alchemy/auth_accessors.rb +1 -1
- data/lib/alchemy/config.rb +1 -1
- data/lib/alchemy/controller_actions.rb +4 -4
- data/lib/alchemy/deprecation.rb +1 -0
- data/lib/alchemy/dragonfly/processors/thumbnail.rb +1 -1
- data/lib/alchemy/element_definition.rb +2 -2
- data/lib/alchemy/engine.rb +16 -1
- data/lib/alchemy/filetypes.rb +7 -7
- data/lib/alchemy/forms/builder.rb +4 -4
- data/lib/alchemy/i18n.rb +6 -4
- data/lib/alchemy/install/tasks.rb +2 -1
- data/lib/alchemy/name_conversions.rb +1 -1
- data/lib/alchemy/page_layout.rb +1 -1
- data/lib/alchemy/permissions.rb +5 -4
- data/lib/alchemy/resource.rb +10 -10
- data/lib/alchemy/resources_helper.rb +7 -7
- data/lib/alchemy/routing_constraints.rb +2 -2
- data/lib/alchemy/seeder.rb +12 -5
- data/lib/alchemy/shell.rb +2 -1
- data/lib/alchemy/taggable.rb +3 -2
- data/lib/alchemy/tasks/tidy.rb +1 -0
- data/lib/alchemy/test_support/capybara_helpers.rb +1 -1
- data/lib/alchemy/test_support/config_stubbing.rb +1 -0
- data/lib/alchemy/test_support/factories/element_factory.rb +4 -0
- data/lib/alchemy/test_support/factories/page_factory.rb +2 -2
- data/lib/alchemy/test_support/having_crop_action_examples.rb +9 -9
- data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +33 -33
- data/lib/alchemy/test_support/integration_helpers.rb +4 -3
- data/lib/alchemy/test_support/shared_contexts.rb +2 -1
- data/lib/alchemy/test_support/shared_dom_ids_examples.rb +9 -9
- data/lib/alchemy/test_support/shared_ingredient_examples.rb +12 -6
- data/lib/alchemy/test_support/shared_uploader_examples.rb +1 -0
- data/lib/alchemy/tinymce.rb +3 -26
- data/lib/alchemy/upgrader/seven_point_zero.rb +13 -23
- data/lib/alchemy/upgrader.rb +1 -11
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy.rb +5 -0
- data/lib/alchemy_cms.rb +3 -1
- data/lib/generators/alchemy/base.rb +3 -2
- data/lib/generators/alchemy/elements/elements_generator.rb +2 -1
- data/lib/generators/alchemy/ingredient/ingredient_generator.rb +1 -0
- data/lib/generators/alchemy/install/files/application.html.erb +2 -2
- data/lib/generators/alchemy/install/install_generator.rb +2 -25
- data/lib/generators/alchemy/module/module_generator.rb +1 -0
- data/lib/generators/alchemy/page_layouts/page_layouts_generator.rb +1 -0
- data/lib/generators/alchemy/site_layouts/site_layouts_generator.rb +1 -0
- data/lib/generators/alchemy/views/views_generator.rb +2 -1
- data/lib/tasks/alchemy/thumbnails.rake +5 -5
- data/lib/tasks/alchemy/tidy.rake +1 -0
- data/lib/tasks/alchemy/upgrade.rake +10 -15
- data/package.json +6 -26
- metadata +80 -31
- data/app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee +0 -93
- data/app/presenters/alchemy/picture_view.rb +0 -88
- data/app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb +0 -10
- data/package/admin.js +0 -32
- data/package/dist/admin.js +0 -16
- data/package/dist/admin.js.map +0 -7
- data/package/src/__tests__/i18n.spec.js +0 -93
- data/package/src/utils/__tests__/ajax.spec.js +0 -168
- data/package/src/utils/__tests__/events.spec.js +0 -38
- /data/{package/src → app/javascript/alchemy_admin}/file_editors.js +0 -0
- /data/{package/src → app/javascript/alchemy_admin}/i18n.js +0 -0
- /data/{package/src → app/javascript/alchemy_admin}/image_cropper.js +0 -0
- /data/{package/src → app/javascript/alchemy_admin}/image_loader.js +0 -0
- /data/{package/src → app/javascript/alchemy_admin}/ingredient_anchor_link.js +0 -0
- /data/{package/src → app/javascript/alchemy_admin}/translations.js +0 -0
- /data/{package/src → app/javascript/alchemy_admin}/utils/ajax.js +0 -0
- /data/{package/src → app/javascript/alchemy_admin}/utils/events.js +0 -0
data/Rakefile
CHANGED
@@ -41,17 +41,12 @@ namespace :alchemy do
|
|
41
41
|
task :prepare do
|
42
42
|
system(
|
43
43
|
<<~BASH
|
44
|
-
yarn install && \
|
45
|
-
yarn link && \
|
46
44
|
cd spec/dummy && \
|
47
|
-
yarn link @alchemy_cms/admin && \
|
48
45
|
export RAILS_ENV=test && \
|
49
46
|
bin/rake db:create && \
|
50
47
|
bin/rake db:environment:set && \
|
51
48
|
bin/rake db:migrate:reset && \
|
52
|
-
bin/rails javascript:install:esbuild && \
|
53
49
|
bin/rails g alchemy:install --skip --skip-demo-files --auto-accept --skip-db-create && \
|
54
|
-
bin/rails javascript:build && \
|
55
50
|
cd -
|
56
51
|
BASH
|
57
52
|
) || fail
|
@@ -81,18 +76,4 @@ namespace :alchemy do
|
|
81
76
|
File.delete(backup)
|
82
77
|
end
|
83
78
|
end
|
84
|
-
|
85
|
-
desc "Release a new Ruby gem and npm package in one command"
|
86
|
-
task :release do
|
87
|
-
require "json"
|
88
|
-
require_relative "lib/alchemy/version"
|
89
|
-
package = File.read("package.json")
|
90
|
-
unless JSON.parse(package)["version"] == Alchemy.version
|
91
|
-
abort "Ruby gem and npm package versions are out of sync! Please fix."
|
92
|
-
end
|
93
|
-
# Release the Ruby gem with bundler
|
94
|
-
Rake::Task["release"].invoke
|
95
|
-
# Publish npm package via CLI
|
96
|
-
system "npm publish"
|
97
|
-
end
|
98
79
|
end
|
data/alchemy_cms.gemspec
CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.summary = "A powerful, userfriendly and flexible CMS for Rails"
|
15
15
|
gem.description = "Alchemy is a powerful, userfriendly and flexible Rails CMS."
|
16
16
|
gem.requirements << "ImageMagick (libmagick), v6.6 or greater."
|
17
|
-
gem.required_ruby_version = ">=
|
17
|
+
gem.required_ruby_version = ">= 3.0.0"
|
18
18
|
gem.license = "BSD New"
|
19
19
|
gem.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^spec/}) }
|
20
20
|
gem.require_paths = ["lib"]
|
@@ -41,6 +41,7 @@ Gem::Specification.new do |gem|
|
|
41
41
|
gem.add_runtime_dependency "dragonfly_svg", ["~> 0.0.4"]
|
42
42
|
gem.add_runtime_dependency "gutentag", ["~> 2.2", ">= 2.2.1"]
|
43
43
|
gem.add_runtime_dependency "handlebars_assets", ["~> 0.23"]
|
44
|
+
gem.add_runtime_dependency "importmap-rails", ["~> 1.2", ">= 1.2.1"]
|
44
45
|
gem.add_runtime_dependency "jquery-rails", ["~> 4.0", ">= 4.0.4"]
|
45
46
|
gem.add_runtime_dependency "jquery-ui-rails", ["~> 6.0"]
|
46
47
|
gem.add_runtime_dependency "kaminari", ["~> 1.1"]
|
@@ -51,7 +52,8 @@ Gem::Specification.new do |gem|
|
|
51
52
|
gem.add_runtime_dependency "sassc-rails", ["~> 2.1"]
|
52
53
|
gem.add_runtime_dependency "simple_form", [">= 4.0", "< 6"]
|
53
54
|
gem.add_runtime_dependency "sprockets", [">= 3.0", "< 5"]
|
54
|
-
gem.add_runtime_dependency "
|
55
|
+
gem.add_runtime_dependency "turbo-rails", [">= 1.4"]
|
56
|
+
gem.add_runtime_dependency "view_component", ["~> 3.0"]
|
55
57
|
|
56
58
|
gem.add_development_dependency "capybara", ["~> 3.0"]
|
57
59
|
gem.add_development_dependency "capybara-screenshot", ["~> 1.0"]
|
@@ -2,7 +2,6 @@
|
|
2
2
|
// ------------------------------
|
3
3
|
//= require jquery2
|
4
4
|
//= require jquery_ujs
|
5
|
-
//= require turbolinks
|
6
5
|
//= require jquery-ui/effects/effect-fade
|
7
6
|
//= require jquery-ui/widgets/draggable
|
8
7
|
//= require jquery-ui/widgets/sortable
|
@@ -38,7 +37,6 @@
|
|
38
37
|
//= require alchemy/alchemy.uploader
|
39
38
|
//= require alchemy/alchemy.preview_window
|
40
39
|
//= require alchemy/alchemy.spinner
|
41
|
-
//= require alchemy/alchemy.tinymce
|
42
40
|
//= require alchemy/alchemy.tooltips
|
43
41
|
//= require alchemy/page_select
|
44
42
|
//= require alchemy/node_select
|
@@ -40,7 +40,7 @@ $.extend Alchemy,
|
|
40
40
|
$form.submit()
|
41
41
|
else if $(element).is("a")
|
42
42
|
callback = ->
|
43
|
-
|
43
|
+
Turbo.visit(element.pathname)
|
44
44
|
if Alchemy.isPageDirty()
|
45
45
|
Alchemy.openConfirmDialog Alchemy.t('page_dirty_notice'),
|
46
46
|
title: Alchemy.t('warning')
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Initialize all onload scripts at once.
|
2
2
|
#
|
3
|
-
# Called at jQuery ready event and
|
3
|
+
# Called at jQuery ready event and Turbo page change event.
|
4
4
|
#
|
5
5
|
Alchemy.Initializer = ->
|
6
6
|
|
@@ -26,13 +26,13 @@ Alchemy.Initializer = ->
|
|
26
26
|
$('select#change_locale').on 'change', (e) ->
|
27
27
|
url = window.location.pathname
|
28
28
|
delimiter = if url.match(/\?/) then '&' else '?'
|
29
|
-
|
29
|
+
Turbo.visit "#{url}#{delimiter}admin_locale=#{$(this).val()}"
|
30
30
|
|
31
31
|
# Site select handler
|
32
32
|
$('select#change_site').on 'change', (e) ->
|
33
33
|
url = window.location.pathname
|
34
34
|
delimiter = if url.match(/\?/) then '&' else '?'
|
35
|
-
|
35
|
+
Turbo.visit "#{url}#{delimiter}site_id=#{$(this).val()}"
|
36
36
|
|
37
37
|
# Submit forms of selects with `data-autosubmit="true"`
|
38
38
|
$('select[data-auto-submit="true"]').on 'change', (e) ->
|
@@ -46,18 +46,11 @@ Alchemy.Initializer = ->
|
|
46
46
|
tagName = (event.target || event.srcElement).tagName
|
47
47
|
key.isPressed('esc') || !(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA')
|
48
48
|
|
49
|
-
|
50
|
-
Turbolinks.enableProgressBar() if Turbolinks.enableProgressBar
|
51
|
-
|
52
|
-
# Turbolinks DOM Ready.
|
53
|
-
# Handle both v2.5(page:change), and v.5.0 (turbolinks:load)
|
54
|
-
$(document).on 'page:change turbolinks:load', ->
|
49
|
+
$(document).on 'turbo:load', ->
|
55
50
|
Alchemy.Initializer()
|
56
51
|
return
|
57
52
|
|
58
|
-
|
59
|
-
# Handle both v2.5(page:receive), and v.5.0 (turbolinks:request-end)
|
60
|
-
$(document).on 'page:receive turbolinks:request-end', ->
|
53
|
+
$(document).on 'turbo:before-fetch-request', ->
|
61
54
|
# Ensure that all tinymce editors get removed before parsing a new page
|
62
55
|
Alchemy.Tinymce.removeFrom $('.has_tinymce')
|
63
56
|
return
|
@@ -59,12 +59,17 @@ class window.Alchemy.LinkDialog extends Alchemy.Dialog
|
|
59
59
|
initPageSelect: ->
|
60
60
|
pageTemplate = HandlebarsTemplates.page
|
61
61
|
element_anchor_placeholder = @$element_anchor.attr('placeholder')
|
62
|
+
if @link_object.dataset.languageId
|
63
|
+
api_url = "#{Alchemy.routes.api_pages_path}?language_id=#{@link_object.dataset.languageId}"
|
64
|
+
else
|
65
|
+
api_url = Alchemy.routes.api_pages_path
|
66
|
+
|
62
67
|
@$internal_link.select2
|
63
68
|
placeholder: Alchemy.t('Search page')
|
64
69
|
allowClear: true
|
65
70
|
minimumInputLength: 3
|
66
71
|
ajax:
|
67
|
-
url:
|
72
|
+
url: api_url
|
68
73
|
datatype: 'json'
|
69
74
|
quietMillis: 300
|
70
75
|
data: (term, page) ->
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Ingredients
|
3
|
+
class AudioView < BaseView
|
4
|
+
def call
|
5
|
+
content_tag(:audio, **html_options) do
|
6
|
+
tag(:source, src: src, type: type)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def render?
|
11
|
+
!!ingredient.attachment
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def src
|
17
|
+
alchemy.show_attachment_path(
|
18
|
+
ingredient.attachment,
|
19
|
+
format: ingredient.attachment.suffix
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def type
|
24
|
+
ingredient.attachment.file_mime_type
|
25
|
+
end
|
26
|
+
|
27
|
+
def html_options
|
28
|
+
{
|
29
|
+
controls: ingredient.controls,
|
30
|
+
autoplay: ingredient.autoplay,
|
31
|
+
loop: ingredient.loop,
|
32
|
+
muted: ingredient.muted
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Ingredients
|
3
|
+
class BaseView < ViewComponent::Base
|
4
|
+
attr_reader :ingredient, :html_options
|
5
|
+
|
6
|
+
delegate :alchemy, to: :helpers
|
7
|
+
delegate :settings, :value, to: :ingredient
|
8
|
+
|
9
|
+
# @param ingredient [Alchemy::Ingredient]
|
10
|
+
# @param html_options [Hash] Options that will be passed to the wrapper tag.
|
11
|
+
def initialize(ingredient, html_options: {})
|
12
|
+
raise ArgumentError, "Ingredient missing!" if ingredient.nil?
|
13
|
+
|
14
|
+
@ingredient = ingredient
|
15
|
+
@html_options = html_options
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
value
|
20
|
+
end
|
21
|
+
|
22
|
+
def render?
|
23
|
+
value.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Fetches value from ingredient settings and allows to merge a value on top of it
|
29
|
+
#
|
30
|
+
# @param key [Symbol] - The settings key you want to fetch the value from
|
31
|
+
# @param value [Object] - A optional value that can override the setting.
|
32
|
+
# Normally passed as into the ingredient view.
|
33
|
+
def settings_value(key, value: nil, default: nil)
|
34
|
+
value.nil? ? settings.fetch(key, default) : value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Ingredients
|
3
|
+
class DatetimeView < BaseView
|
4
|
+
attr_reader :date_format
|
5
|
+
|
6
|
+
# @param ingredient [Alchemy::Ingredient]
|
7
|
+
# @param date_format [String] The date format to use. Use either a strftime format string, a I18n format symbol or "rfc822".
|
8
|
+
def initialize(ingredient, date_format: nil, html_options: {})
|
9
|
+
super(ingredient)
|
10
|
+
@date_format = settings_value(:date_format, value: date_format)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
if date_format == "rfc822"
|
15
|
+
ingredient.value.to_s(:rfc822)
|
16
|
+
else
|
17
|
+
::I18n.l(ingredient.value, format: date_format)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Ingredients
|
3
|
+
class FileView < BaseView
|
4
|
+
delegate :attachment, to: :ingredient
|
5
|
+
|
6
|
+
# @param ingredient [Alchemy::Ingredient]
|
7
|
+
# @param link_text [String] The link text. If not given, the ingredients link_text setting or the attachments name will be used.
|
8
|
+
# @param html_options [Hash] Options that will be passed to the a tag.
|
9
|
+
def initialize(ingredient, link_text: nil, html_options: {})
|
10
|
+
super(ingredient, html_options: html_options)
|
11
|
+
@link_text = settings_value(:link_text, value: link_text, default: attachment&.name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
link_to(
|
16
|
+
link_text,
|
17
|
+
attachment.url(
|
18
|
+
download: true,
|
19
|
+
name: attachment.slug,
|
20
|
+
format: attachment.suffix
|
21
|
+
),
|
22
|
+
{
|
23
|
+
class: ingredient.css_class.presence,
|
24
|
+
title: ingredient.title.presence
|
25
|
+
}.merge(html_options)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def render?
|
30
|
+
!attachment.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def link_text
|
36
|
+
ingredient.link_text.presence || @link_text
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Ingredients
|
3
|
+
class HeadlineView < BaseView
|
4
|
+
def initialize(ingredient, level: nil, html_options: {})
|
5
|
+
super(ingredient, html_options: html_options)
|
6
|
+
@level = level
|
7
|
+
end
|
8
|
+
|
9
|
+
def call
|
10
|
+
content_tag "h#{@level || ingredient.level}",
|
11
|
+
ingredient.value,
|
12
|
+
id: ingredient.dom_id.presence,
|
13
|
+
class: [
|
14
|
+
ingredient.size ? "h#{ingredient.size}" : nil,
|
15
|
+
html_options[:class]
|
16
|
+
]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Ingredients
|
3
|
+
class LinkView < BaseView
|
4
|
+
attr_reader :link_text
|
5
|
+
|
6
|
+
# @param ingredient [Alchemy::Ingredient]
|
7
|
+
# @param text [String] The link text. If not given, the ingredient's text setting or the value will be used.
|
8
|
+
# @param html_options [Hash] Options that will be passed to the a tag.
|
9
|
+
def initialize(ingredient, text: nil, html_options: {})
|
10
|
+
super(ingredient, html_options: html_options)
|
11
|
+
@link_text = settings_value(:text, value: text, default: value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
link_to(link_text, value, {target: link_target}.merge(html_options))
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def link_target
|
21
|
+
(ingredient.link_target == "blank") ? "_blank" : nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module Ingredients
|
5
|
+
# Renders a picture ingredient view
|
6
|
+
class PictureView < BaseView
|
7
|
+
attr_reader :ingredient,
|
8
|
+
:show_caption,
|
9
|
+
:disable_link,
|
10
|
+
:srcset,
|
11
|
+
:sizes,
|
12
|
+
:html_options,
|
13
|
+
:picture_options,
|
14
|
+
:picture
|
15
|
+
|
16
|
+
# @param ingredient [Alchemy::Ingredient]
|
17
|
+
# @param show_caption [Boolean] (true) Whether to show a caption or not, even if present on the picture.
|
18
|
+
# @param disable_link [Boolean] (false) Whether to disable the link even if the picture has a link.
|
19
|
+
# @param srcset [Array<String>] An array of srcset sizes that will generate variants of the picture.
|
20
|
+
# @param sizes [Array<String>] An array of sizes that will be passed to the img tag.
|
21
|
+
# @param picture_options [Hash] Options that will be passed to the picture url. See {Alchemy::PictureVariant} for options.
|
22
|
+
# @param html_options [Hash] Options that will be passed to the img tag.
|
23
|
+
# @see Alchemy::PictureVariant
|
24
|
+
def initialize(
|
25
|
+
ingredient,
|
26
|
+
show_caption: nil,
|
27
|
+
disable_link: nil,
|
28
|
+
srcset: nil,
|
29
|
+
sizes: nil,
|
30
|
+
picture_options: {},
|
31
|
+
html_options: {}
|
32
|
+
)
|
33
|
+
super(ingredient)
|
34
|
+
@show_caption = settings_value(:show_caption, value: show_caption, default: true)
|
35
|
+
@disable_link = settings_value(:disable_link, value: disable_link, default: false)
|
36
|
+
@srcset = settings_value(:srcset, value: srcset, default: [])
|
37
|
+
@sizes = settings_value(:sizes, value: sizes, default: [])
|
38
|
+
@picture_options = picture_options || {}
|
39
|
+
@html_options = html_options || {}
|
40
|
+
@picture = ingredient.picture
|
41
|
+
end
|
42
|
+
|
43
|
+
def call
|
44
|
+
return if picture.blank?
|
45
|
+
|
46
|
+
output = caption ? img_tag + caption : img_tag
|
47
|
+
|
48
|
+
if is_linked?
|
49
|
+
output = link_to(output, url_for(ingredient.link), {
|
50
|
+
title: ingredient.link_title.presence,
|
51
|
+
target: (ingredient.link_target == "blank") ? "_blank" : nil,
|
52
|
+
data: {link_target: ingredient.link_target.presence}
|
53
|
+
})
|
54
|
+
end
|
55
|
+
|
56
|
+
if caption
|
57
|
+
content_tag(:figure, output, {class: ingredient.css_class.presence}.merge(html_options))
|
58
|
+
else
|
59
|
+
output
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def caption
|
66
|
+
return unless show_caption?
|
67
|
+
|
68
|
+
@_caption ||= content_tag(:figcaption, ingredient.caption)
|
69
|
+
end
|
70
|
+
|
71
|
+
def src
|
72
|
+
ingredient.picture_url(picture_options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def img_tag
|
76
|
+
@_img_tag ||= image_tag(
|
77
|
+
src, {
|
78
|
+
alt: alt_text,
|
79
|
+
title: ingredient.title.presence,
|
80
|
+
class: caption ? nil : ingredient.css_class.presence,
|
81
|
+
srcset: srcset_options.join(", ").presence,
|
82
|
+
sizes: sizes.join(", ").presence
|
83
|
+
}.merge(caption ? {} : html_options)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def show_caption?
|
88
|
+
show_caption && ingredient.caption.present?
|
89
|
+
end
|
90
|
+
|
91
|
+
def is_linked?
|
92
|
+
!disable_link && ingredient.link.present?
|
93
|
+
end
|
94
|
+
|
95
|
+
def srcset_options
|
96
|
+
srcset.map do |size|
|
97
|
+
url = ingredient.picture_url(size: size)
|
98
|
+
width, height = size.split("x")
|
99
|
+
width.present? ? "#{url} #{width}w" : "#{url} #{height}h"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def alt_text
|
104
|
+
ingredient.alt_tag.presence || html_options.delete(:alt) || ingredient.picture.name&.humanize
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Ingredients
|
3
|
+
class RichtextView < BaseView
|
4
|
+
attr_reader :plain_text
|
5
|
+
|
6
|
+
# @param ingredient [Alchemy::Ingredient]
|
7
|
+
# @param plain_text [Boolean] (false) Whether to show as plain text or with markup
|
8
|
+
def initialize(ingredient, plain_text: nil, html_options: {})
|
9
|
+
super(ingredient)
|
10
|
+
@plain_text = settings_value(:plain_text, value: plain_text, default: false)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
if plain_text
|
15
|
+
ingredient.stripped_body
|
16
|
+
else
|
17
|
+
value.to_s.html_safe
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Ingredients
|
3
|
+
class TextView < BaseView
|
4
|
+
attr_reader :disable_link
|
5
|
+
|
6
|
+
delegate :dom_id, :link, :link_title, :link_target,
|
7
|
+
to: :ingredient
|
8
|
+
|
9
|
+
# @param ingredient [Alchemy::Ingredient]
|
10
|
+
# @param disable_link [Boolean] (false) Whether to disable the link even if the picture has a link.
|
11
|
+
# @param html_options [Hash] Options that will be passed to the a tag.
|
12
|
+
def initialize(ingredient, disable_link: nil, html_options: {})
|
13
|
+
super(ingredient, html_options: html_options)
|
14
|
+
@disable_link = settings_value(:disable_link, value: disable_link, default: false)
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
if disable_link?
|
19
|
+
dom_id.present? ? anchor : value
|
20
|
+
else
|
21
|
+
link_to(value, url_for(link), {
|
22
|
+
id: dom_id.presence,
|
23
|
+
title: link_title,
|
24
|
+
target: ((link_target == "blank") ? "_blank" : nil),
|
25
|
+
data: {link_target: link_target}
|
26
|
+
}.merge(html_options))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def anchor
|
33
|
+
content_tag(:a, value, {id: dom_id}.merge(html_options))
|
34
|
+
end
|
35
|
+
|
36
|
+
def disable_link?
|
37
|
+
link.blank? || disable_link
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Ingredients
|
3
|
+
class VideoView < BaseView
|
4
|
+
delegate :attachment, to: :ingredient
|
5
|
+
|
6
|
+
def call
|
7
|
+
content_tag(:video, html_options) do
|
8
|
+
tag(:source, src: src, type: attachment.file_mime_type)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def render?
|
13
|
+
!attachment.nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def src
|
19
|
+
alchemy.show_attachment_path(
|
20
|
+
attachment,
|
21
|
+
format: attachment.suffix
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def html_options
|
26
|
+
{
|
27
|
+
controls: ingredient.controls,
|
28
|
+
autoplay: ingredient.autoplay,
|
29
|
+
loop: ingredient.loop,
|
30
|
+
muted: ingredient.muted,
|
31
|
+
playsinline: ingredient.playsinline,
|
32
|
+
preload: ingredient.preload.presence,
|
33
|
+
width: ingredient.width.presence,
|
34
|
+
height: ingredient.height.presence
|
35
|
+
}.merge(@html_options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -52,7 +52,7 @@ module Alchemy
|
|
52
52
|
render_errors_or_redirect(
|
53
53
|
@attachment,
|
54
54
|
admin_attachments_path(search_filter_params),
|
55
|
-
Alchemy.t("File successfully updated")
|
55
|
+
Alchemy.t("File successfully updated")
|
56
56
|
)
|
57
57
|
end
|
58
58
|
end
|
@@ -68,7 +68,7 @@ module Alchemy
|
|
68
68
|
@attachment = Attachment.find(params[:id])
|
69
69
|
send_file @attachment.file.path, {
|
70
70
|
filename: @attachment.file_name,
|
71
|
-
type: @attachment.file_mime_type
|
71
|
+
type: @attachment.file_mime_type
|
72
72
|
}
|
73
73
|
end
|
74
74
|
|
@@ -77,7 +77,7 @@ module Alchemy
|
|
77
77
|
def search_filter_params
|
78
78
|
@_search_filter_params ||= params.except(*COMMON_SEARCH_FILTER_EXCLUDES + [:attachment]).permit(
|
79
79
|
*common_search_filter_includes + [
|
80
|
-
:form_field_id
|
80
|
+
:form_field_id
|
81
81
|
]
|
82
82
|
)
|
83
83
|
end
|