alchemy_cms 7.4.10 → 8.0.0.b
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.
- checksums.yaml +4 -4
- data/README.md +16 -5
- data/app/assets/builds/alchemy/admin/page-select.css +1 -1
- data/app/assets/builds/alchemy/admin/print.css +1 -1
- data/app/assets/builds/alchemy/admin.css +2 -2
- data/app/assets/builds/alchemy/dark-theme.css +1 -0
- data/app/assets/builds/alchemy/light-theme.css +1 -0
- data/app/assets/builds/alchemy/theme.css +1 -0
- data/app/assets/builds/alchemy/welcome.css +1 -1
- data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
- data/app/assets/builds/tinymce/skins/content/alchemy-dark/content.min.css +1 -0
- data/app/assets/builds/tinymce/skins/ui/alchemy/content.min.css +1 -0
- data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css +1 -1
- data/app/assets/builds/tinymce/skins/ui/alchemy-dark/content.min.css +1 -0
- data/app/assets/builds/tinymce/skins/ui/alchemy-dark/skin.min.css +1 -0
- data/app/assets/config/alchemy_manifest.js +0 -2
- data/app/assets/images/alchemy/element_icons/default.svg +1 -0
- data/app/assets/images/alchemy/icons-sprite.svg +1 -0
- data/app/components/alchemy/admin/element_select.rb +39 -0
- data/app/components/alchemy/admin/resource/applied_filter.rb +29 -0
- data/app/components/alchemy/admin/resource/checkbox_filter.rb +36 -0
- data/app/components/alchemy/admin/resource/datepicker_filter.rb +42 -0
- data/app/components/alchemy/admin/resource/select_filter.rb +43 -0
- data/app/components/alchemy/admin/toolbar_button.rb +5 -2
- data/app/components/alchemy/ingredients/number_view.rb +18 -0
- data/app/controllers/alchemy/admin/attachments_controller.rb +10 -15
- data/app/controllers/alchemy/admin/clipboard_controller.rb +2 -6
- data/app/controllers/alchemy/admin/elements_controller.rb +3 -1
- data/app/controllers/alchemy/admin/languages_controller.rb +1 -1
- data/app/controllers/alchemy/admin/pages_controller.rb +15 -15
- data/app/controllers/alchemy/admin/pictures_controller.rb +27 -37
- data/app/controllers/alchemy/admin/resources_controller.rb +16 -106
- data/app/controllers/alchemy/attachments_controller.rb +43 -14
- data/app/controllers/alchemy/messages_controller.rb +1 -1
- data/app/controllers/alchemy/pages_controller.rb +26 -4
- data/app/controllers/concerns/alchemy/admin/resource_filter.rb +93 -0
- data/app/decorators/alchemy/element_editor.rb +5 -48
- data/app/decorators/alchemy/ingredient_editor.rb +3 -53
- data/app/helpers/alchemy/admin/attachments_helper.rb +5 -5
- data/app/helpers/alchemy/admin/base_helper.rb +14 -84
- data/app/helpers/alchemy/admin/pages_helper.rb +1 -1
- data/app/helpers/alchemy/base_helper.rb +0 -30
- data/app/helpers/alchemy/elements_block_helper.rb +0 -14
- data/app/helpers/alchemy/pages_helper.rb +1 -1
- data/{lib → app/helpers}/alchemy/resources_helper.rb +5 -45
- data/app/javascript/alchemy_admin/components/action.js +2 -0
- data/app/javascript/alchemy_admin/components/alchemy_html_element.js +3 -3
- data/app/javascript/alchemy_admin/components/auto_submit.js +20 -0
- data/app/javascript/alchemy_admin/components/datepicker.js +18 -7
- data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +8 -7
- data/app/javascript/alchemy_admin/components/element_editor.js +25 -15
- data/app/javascript/alchemy_admin/components/element_select.js +43 -0
- data/app/javascript/alchemy_admin/components/index.js +3 -0
- data/app/javascript/alchemy_admin/components/link_buttons.js +6 -2
- data/app/javascript/alchemy_admin/components/remote_select.js +9 -2
- data/app/javascript/alchemy_admin/components/tags_autocomplete.js +5 -1
- data/app/javascript/alchemy_admin/components/tinymce.js +93 -14
- data/app/javascript/alchemy_admin/components/update_check.js +42 -0
- data/app/javascript/alchemy_admin/components/uploader/file_upload.js +15 -8
- data/app/javascript/alchemy_admin/components/uploader/progress.js +12 -6
- data/app/javascript/alchemy_admin/components/uploader.js +4 -2
- data/app/javascript/alchemy_admin/confirm_dialog.js +27 -57
- data/app/javascript/alchemy_admin/dialog.js +1 -1
- data/app/javascript/alchemy_admin/dirty.js +3 -2
- data/app/javascript/alchemy_admin/file_editors.js +1 -1
- data/app/javascript/alchemy_admin/i18n.js +15 -16
- data/app/javascript/alchemy_admin/image_loader.js +4 -2
- data/app/javascript/alchemy_admin/initializer.js +1 -49
- data/app/javascript/alchemy_admin/picture_editors.js +7 -4
- data/app/javascript/alchemy_admin/picture_selector.js +4 -4
- data/app/javascript/alchemy_admin/utils/ajax.js +51 -44
- data/app/javascript/alchemy_admin.js +3 -8
- data/app/jobs/alchemy/delete_picture_job.rb +12 -0
- data/app/models/alchemy/admin/filters/base.rb +38 -0
- data/app/models/alchemy/admin/filters/checkbox.rb +24 -0
- data/app/models/alchemy/admin/filters/datepicker.rb +53 -0
- data/app/models/alchemy/admin/filters/select.rb +70 -0
- data/app/models/alchemy/admin/resource_name.rb +27 -0
- data/app/models/alchemy/attachment.rb +49 -44
- data/app/models/alchemy/base_record.rb +2 -0
- data/app/models/alchemy/element/definitions.rb +1 -1
- data/app/models/alchemy/element/element_ingredients.rb +6 -6
- data/app/models/alchemy/element/presenters.rb +3 -12
- data/app/models/alchemy/element.rb +10 -27
- data/app/models/alchemy/element_definition.rb +190 -0
- data/app/models/alchemy/ingredient.rb +10 -43
- data/app/models/alchemy/ingredient_definition.rb +134 -0
- data/app/models/alchemy/ingredient_validator.rb +7 -3
- data/app/models/alchemy/ingredients/number.rb +19 -0
- data/app/models/alchemy/language.rb +2 -21
- data/app/models/alchemy/message.rb +3 -7
- data/app/models/alchemy/node.rb +1 -1
- data/app/models/alchemy/page/{page_layouts.rb → definitions.rb} +12 -19
- data/app/models/alchemy/page/fixed_attributes.rb +1 -1
- data/app/models/alchemy/page/page_elements.rb +13 -14
- data/app/models/alchemy/page/page_naming.rb +3 -11
- data/app/models/alchemy/page/page_natures.rb +20 -15
- data/app/models/alchemy/page/page_scopes.rb +1 -1
- data/app/models/alchemy/page.rb +12 -39
- data/app/models/alchemy/page_definition.rb +115 -0
- data/app/models/alchemy/picture.rb +71 -99
- data/app/models/alchemy/picture_variant.rb +115 -5
- data/{lib → app/models}/alchemy/resource.rb +4 -18
- data/{lib → app/models}/alchemy/searchable_resource.rb +15 -0
- data/app/models/alchemy/site/layout.rb +5 -5
- data/app/models/alchemy/site.rb +1 -21
- data/app/models/alchemy/storage_adapter/active_storage/attachment_url.rb +41 -0
- data/app/models/alchemy/storage_adapter/active_storage/picture_url.rb +55 -0
- data/app/models/alchemy/storage_adapter/active_storage/preprocessor.rb +40 -0
- data/app/models/alchemy/storage_adapter/active_storage.rb +173 -0
- data/app/models/alchemy/{attachment/url.rb → storage_adapter/dragonfly/attachment_url.rb} +12 -12
- data/app/models/alchemy/storage_adapter/dragonfly/picture_url.rb +75 -0
- data/app/models/alchemy/{picture → storage_adapter/dragonfly}/preprocessor.rb +4 -4
- data/app/models/alchemy/storage_adapter/dragonfly.rb +205 -0
- data/app/models/alchemy/storage_adapter.rb +74 -0
- data/app/models/concerns/alchemy/picture_thumbnails.rb +19 -6
- data/app/models/concerns/alchemy/relatable_resource.rb +28 -0
- data/app/serializers/alchemy/element_serializer.rb +0 -1
- data/app/services/alchemy/dragonfly_to_image_processing.rb +100 -0
- data/app/stylesheets/alchemy/_custom-properties.scss +162 -0
- data/app/stylesheets/alchemy/_defaults.scss +3 -0
- data/app/stylesheets/alchemy/_extends.scss +69 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/_mixins.scss +40 -68
- data/app/stylesheets/alchemy/_themes.scss +540 -0
- data/app/stylesheets/alchemy/_variables.scss +5 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/archive.scss +45 -42
- data/app/stylesheets/alchemy/admin/attachments.scss +17 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/base.scss +20 -15
- data/app/stylesheets/alchemy/admin/buttons.scss +135 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/clipboard.scss +2 -2
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/dashboard.scss +13 -16
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/dialogs.scss +33 -16
- data/app/stylesheets/alchemy/admin/element-select.scss +11 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/elements.scss +239 -133
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/errors.scss +5 -5
- data/app/stylesheets/alchemy/admin/filters.scss +57 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/flatpickr.scss +54 -76
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/form_fields.scss +10 -11
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/forms.scss +28 -21
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/frame.scss +20 -18
- data/app/stylesheets/alchemy/admin/hints.scss +5 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/icons.scss +1 -1
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/image_library.scss +21 -61
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/images.scss +1 -1
- data/app/stylesheets/alchemy/admin/labels.scss +5 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/lists.scss +3 -3
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/navigation.scss +55 -59
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/node-select.scss +1 -10
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/nodes.scss +21 -18
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/notices.scss +20 -19
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/page-select.scss +18 -2
- data/app/stylesheets/alchemy/admin/pagination.scss +137 -0
- data/app/stylesheets/alchemy/admin/preview_window.scss +46 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/print.scss +1 -1
- data/app/stylesheets/alchemy/admin/resource_info.scss +148 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/search.scss +10 -7
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/selects.scss +85 -46
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/shoelace.scss +37 -68
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/sitemap.scss +39 -34
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/tables.scss +9 -7
- data/app/stylesheets/alchemy/admin/tags.scss +143 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/toolbar.scss +6 -6
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/typography.scss +3 -6
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/upload.scss +7 -5
- data/app/stylesheets/alchemy/admin.scss +44 -0
- data/app/stylesheets/alchemy/dark-theme.scss +5 -0
- data/app/stylesheets/alchemy/light-theme.scss +6 -0
- data/app/stylesheets/alchemy/theme.scss +13 -0
- data/app/stylesheets/alchemy/welcome.scss +75 -0
- data/app/stylesheets/tinymce/skins/content/alchemy/content.scss +69 -0
- data/app/{assets/stylesheets/tinymce/skins/content/alchemy → stylesheets/tinymce/skins/content/alchemy-dark}/content.scss +12 -12
- data/app/stylesheets/tinymce/skins/ui/alchemy/content.scss +1 -0
- data/app/{assets/stylesheets → stylesheets}/tinymce/skins/ui/alchemy/skin.scss +158 -176
- data/app/stylesheets/tinymce/skins/ui/alchemy-dark/content.scss +1 -0
- data/app/stylesheets/tinymce/skins/ui/alchemy-dark/skin.scss +3784 -0
- data/app/views/alchemy/admin/attachments/_files_list.html.erb +22 -12
- data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +1 -1
- data/app/views/alchemy/admin/attachments/assign.js.erb +4 -3
- data/app/views/alchemy/admin/attachments/show.html.erb +55 -43
- data/app/views/alchemy/admin/{elements/_clipboard_button.html.erb → clipboard/_button.html.erb} +3 -5
- data/app/views/alchemy/admin/clipboard/_update_nested_element_button.turbo_stream.erb +11 -0
- data/app/views/alchemy/admin/clipboard/clear.turbo_stream.erb +4 -0
- data/app/views/alchemy/admin/clipboard/index.html.erb +15 -13
- data/app/views/alchemy/admin/clipboard/insert.turbo_stream.erb +18 -0
- data/app/views/alchemy/admin/clipboard/remove.turbo_stream.erb +9 -0
- data/app/views/alchemy/admin/crop.html.erb +1 -1
- data/app/views/alchemy/admin/dashboard/info.html.erb +17 -31
- data/app/views/alchemy/admin/elements/_element.html.erb +4 -8
- data/app/views/alchemy/admin/elements/_form.html.erb +9 -9
- data/app/views/alchemy/admin/elements/_header.html.erb +5 -1
- data/app/views/alchemy/admin/elements/_toolbar.html.erb +4 -6
- data/app/views/alchemy/admin/elements/create.turbo_stream.erb +2 -1
- data/app/views/alchemy/admin/elements/index.html.erb +2 -2
- data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +3 -16
- data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +0 -9
- data/app/views/alchemy/admin/languages/_form.html.erb +1 -1
- data/app/views/alchemy/admin/languages/_table.html.erb +1 -1
- data/app/views/alchemy/admin/languages/index.html.erb +5 -2
- data/app/views/alchemy/admin/layoutpages/index.html.erb +1 -12
- data/app/views/alchemy/admin/pages/_form.html.erb +2 -2
- data/app/views/alchemy/admin/pages/_page.html.erb +2 -3
- data/app/views/alchemy/admin/pages/_toolbar.html.erb +1 -15
- data/app/views/alchemy/admin/pages/index.html.erb +1 -1
- data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +9 -12
- data/app/views/alchemy/admin/partials/_search_form.html.erb +4 -9
- data/app/views/alchemy/admin/pictures/_archive.html.erb +16 -29
- data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +3 -7
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_form.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_infos.html.erb +21 -52
- data/app/views/alchemy/admin/pictures/_library_sidebar.html.erb +7 -0
- data/app/views/alchemy/admin/pictures/_picture.html.erb +14 -20
- data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +20 -16
- data/app/views/alchemy/admin/pictures/_sorting_select.html.erb +13 -0
- data/app/views/alchemy/admin/pictures/_tag_list.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +1 -6
- data/app/views/alchemy/admin/pictures/index.html.erb +5 -19
- data/app/views/alchemy/admin/pictures/show.html.erb +10 -5
- data/app/views/alchemy/admin/resources/_applied_filters.html.erb +8 -0
- data/app/views/alchemy/admin/resources/_filter_bar.html.erb +5 -25
- data/app/views/alchemy/admin/resources/_pagination.html.erb +6 -0
- data/app/views/alchemy/admin/resources/_per_page_select.html.erb +4 -2
- data/app/views/alchemy/admin/resources/_resource_table.html.erb +1 -1
- data/app/views/alchemy/admin/resources/_resource_usage_info.html.erb +36 -0
- data/app/views/alchemy/admin/resources/_table_header.html.erb +1 -15
- data/app/views/alchemy/admin/sites/index.html.erb +5 -1
- data/app/views/alchemy/admin/styleguide/index.html.erb +118 -58
- data/app/views/alchemy/admin/tags/index.html.erb +1 -1
- data/app/views/alchemy/admin/tinymce/_setup.html.erb +7 -7
- data/app/{javascript/alchemy_admin/locales/en.js → views/alchemy/admin/translations/_en.js} +5 -2
- data/app/views/alchemy/admin/uploader/_button.html.erb +1 -1
- data/app/views/alchemy/admin/uploader/_setup.html.erb +4 -4
- data/app/views/alchemy/base/error_notice.html.erb +1 -1
- data/app/views/alchemy/ingredients/_number_editor.html.erb +24 -0
- data/app/views/alchemy/no_index.html.erb +31 -0
- data/app/views/alchemy/welcome.html.erb +12 -10
- data/app/views/kaminari/alchemy/_first_page.html.erb +5 -3
- data/app/views/kaminari/alchemy/_last_page.html.erb +5 -3
- data/app/views/kaminari/alchemy/_next_page.html.erb +5 -3
- data/app/views/kaminari/alchemy/_paginator.html.erb +18 -13
- data/app/views/kaminari/alchemy/_prev_page.html.erb +5 -3
- data/app/views/layouts/alchemy/admin.html.erb +25 -24
- data/config/alchemy/config.yml +3 -2
- data/config/initializers/dragonfly.rb +0 -1
- data/config/initializers/mime_types.rb +1 -0
- data/config/locales/alchemy.en.yml +57 -21
- data/config/routes.rb +0 -2
- data/db/migrate/20250905140323_add_created_at_index_to_pictures_and_attachments.rb +14 -0
- data/lib/alchemy/admin/preview_url.rb +4 -5
- data/lib/alchemy/cache_digests/template_tracker.rb +6 -9
- data/lib/alchemy/config_missing.rb +14 -0
- data/lib/alchemy/configuration/base_option.rb +24 -0
- data/lib/alchemy/configuration/boolean_option.rb +16 -0
- data/lib/alchemy/configuration/class_option.rb +15 -0
- data/lib/alchemy/configuration/class_set_option.rb +46 -0
- data/lib/alchemy/configuration/integer_list_option.rb +13 -0
- data/lib/alchemy/configuration/integer_option.rb +12 -0
- data/lib/alchemy/configuration/list_option.rb +22 -0
- data/lib/alchemy/configuration/regexp_option.rb +11 -0
- data/lib/alchemy/configuration/string_list_option.rb +13 -0
- data/lib/alchemy/configuration/string_option.rb +11 -0
- data/lib/alchemy/configuration.rb +115 -0
- data/lib/alchemy/configuration_methods.rb +3 -1
- data/lib/alchemy/configurations/default_language.rb +12 -0
- data/lib/alchemy/configurations/default_site.rb +10 -0
- data/lib/alchemy/configurations/format_matchers.rb +11 -0
- data/lib/alchemy/configurations/mailer.rb +16 -0
- data/lib/alchemy/configurations/main.rb +223 -0
- data/lib/alchemy/configurations/page_cache.rb +19 -0
- data/lib/alchemy/configurations/preview.rb +32 -0
- data/lib/alchemy/configurations/sitemap.rb +10 -0
- data/lib/alchemy/configurations/uploader.rb +34 -0
- data/lib/alchemy/engine.rb +81 -24
- data/lib/alchemy/hints.rb +3 -7
- data/lib/alchemy/install/tasks.rb +0 -12
- data/lib/alchemy/on_page_layout.rb +2 -2
- data/lib/alchemy/propshaft/tinymce_asset.rb +15 -0
- data/lib/alchemy/seeder.rb +2 -2
- data/lib/alchemy/tasks/tidy.rb +18 -0
- data/lib/alchemy/tasks/usage.rb +4 -4
- data/lib/alchemy/test_support/config_stubbing.rb +1 -7
- data/lib/alchemy/test_support/factories/attachment_factory.rb +13 -2
- data/lib/alchemy/test_support/factories/language_factory.rb +1 -1
- data/lib/alchemy/test_support/factories/page_factory.rb +2 -3
- data/lib/alchemy/test_support/factories/picture_factory.rb +31 -2
- data/lib/alchemy/test_support/factories/site_factory.rb +2 -2
- data/lib/alchemy/test_support/having_crop_action_examples.rb +2 -2
- data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +80 -26
- data/lib/alchemy/test_support/relatable_resource_examples.rb +58 -0
- data/lib/alchemy/test_support/shared_ingredient_examples.rb +5 -5
- data/lib/alchemy/tinymce.rb +0 -1
- data/lib/alchemy/upgrader/eight_zero.rb +14 -0
- data/lib/alchemy/upgrader.rb +33 -20
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy.rb +185 -172
- data/lib/alchemy_cms.rb +1 -7
- data/lib/generators/alchemy/ingredient/ingredient_generator.rb +0 -3
- data/lib/generators/alchemy/install/files/_article.html.erb +6 -4
- data/lib/generators/alchemy/install/files/alchemy.en.yml +22 -3
- data/lib/generators/alchemy/install/files/application.html.erb +5 -0
- data/lib/generators/alchemy/install/install_generator.rb +25 -23
- data/lib/generators/alchemy/install/templates/alchemy.rb.tt +200 -0
- data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +0 -1
- data/lib/generators/alchemy/install/templates/elements.yml.tt +3 -1
- data/lib/generators/alchemy/install/templates/menus.yml.tt +1 -1
- data/lib/generators/alchemy/install/templates/page_layouts.yml.tt +2 -2
- data/lib/generators/alchemy/page_layouts/page_layouts_generator.rb +2 -2
- data/lib/tasks/alchemy/assets.rake +14 -0
- data/lib/tasks/alchemy/tidy.rake +6 -0
- data/lib/tasks/alchemy/upgrade.rake +12 -47
- data/vendor/assets/stylesheets/tinymce/skins/content/dark/content.min.css +1 -0
- data/vendor/assets/stylesheets/tinymce/skins/content/default/content.min.css +1 -0
- data/vendor/assets/stylesheets/tinymce/skins/ui/oxide/skin.min.css +1 -0
- data/vendor/assets/stylesheets/tinymce/skins/ui/oxide-dark/content.min.css +1 -0
- data/vendor/assets/stylesheets/tinymce/skins/ui/oxide-dark/skin.min.css +1 -0
- data/vendor/javascript/clipboard.min.js +1 -1
- data/vendor/javascript/cropperjs.min.js +1 -1
- data/vendor/javascript/handlebars.min.js +3 -3
- data/vendor/javascript/jquery.min.js +1 -1
- data/vendor/javascript/select2.min.js +3 -3
- data/vendor/javascript/shoelace.min.js +92 -76
- data/vendor/javascript/sortable.min.js +2 -2
- data/vendor/javascript/tinymce.min.js +1 -1
- data/vendor/javascript/ungap-custom-elements.min.js +2 -2
- metadata +223 -208
- data/CHANGELOG.md +0 -2041
- data/CODE_OF_CONDUCT.md +0 -13
- data/CONTRIBUTING.md +0 -73
- data/Gemfile +0 -71
- data/Rakefile +0 -102
- data/SECURITY.md +0 -13
- data/alchemy_cms.gemspec +0 -88
- data/app/assets/builds/alchemy/admin/page-select.css.map +0 -1
- data/app/assets/builds/alchemy/admin/print.css.map +0 -1
- data/app/assets/builds/alchemy/admin.css.map +0 -1
- data/app/assets/builds/alchemy/custom-properties.css +0 -1
- data/app/assets/builds/alchemy/custom-properties.css.map +0 -1
- data/app/assets/builds/alchemy/welcome.css.map +0 -1
- data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css.map +0 -1
- data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css.map +0 -1
- data/app/assets/javascripts/alchemy/admin.js +0 -10
- data/app/assets/stylesheets/alchemy/_defaults.scss +0 -3
- data/app/assets/stylesheets/alchemy/_deprecated_variables.scss +0 -45
- data/app/assets/stylesheets/alchemy/_deprecation.scss +0 -17
- data/app/assets/stylesheets/alchemy/_extends.scss +0 -62
- data/app/assets/stylesheets/alchemy/_variables.scss +0 -201
- data/app/assets/stylesheets/alchemy/admin/attachments.scss +0 -40
- data/app/assets/stylesheets/alchemy/admin/buttons.scss +0 -123
- data/app/assets/stylesheets/alchemy/admin/hints.scss +0 -5
- data/app/assets/stylesheets/alchemy/admin/labels.scss +0 -3
- data/app/assets/stylesheets/alchemy/admin/pagination.scss +0 -92
- data/app/assets/stylesheets/alchemy/admin/preview_window.scss +0 -33
- data/app/assets/stylesheets/alchemy/admin/resource_info.scss +0 -42
- data/app/assets/stylesheets/alchemy/admin/tags.scss +0 -158
- data/app/assets/stylesheets/alchemy/admin.scss +0 -42
- data/app/assets/stylesheets/alchemy/custom-properties.css +0 -98
- data/app/assets/stylesheets/alchemy/welcome.scss +0 -57
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.css +0 -711
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.css +0 -705
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.min.css +0 -7
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.min.css +0 -7
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.css +0 -29
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.min.css +0 -7
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.css +0 -677
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.min.css +0 -7
- data/app/controllers/alchemy/elements_controller.rb +0 -32
- data/app/helpers/alchemy/admin/elements_helper.rb +0 -25
- data/app/models/alchemy/element/dom_id.rb +0 -31
- data/app/models/alchemy/picture/calculations.rb +0 -49
- data/app/models/alchemy/picture/transformations.rb +0 -115
- data/app/models/alchemy/picture/url.rb +0 -54
- data/app/views/alchemy/admin/attachments/destroy.js.erb +0 -1
- data/app/views/alchemy/admin/clipboard/clear.js.erb +0 -3
- data/app/views/alchemy/admin/clipboard/insert.js.erb +0 -29
- data/app/views/alchemy/admin/clipboard/remove.js.erb +0 -10
- data/app/views/alchemy/admin/resources/_filter.html.erb +0 -12
- data/app/views/alchemy/admin/resources/_resource.html.erb +0 -34
- data/app/views/alchemy/admin/resources/_table.html.erb +0 -29
- data/app/views/alchemy/elements/show.html.erb +0 -1
- data/app/views/alchemy/elements/show.js.erb +0 -1
- data/app/views/alchemy/ingredients/_audio_view.html.erb +0 -1
- data/app/views/alchemy/ingredients/_boolean_view.html.erb +0 -1
- data/app/views/alchemy/ingredients/_datetime_view.html.erb +0 -3
- data/app/views/alchemy/ingredients/_file_view.html.erb +0 -4
- data/app/views/alchemy/ingredients/_headline_view.html.erb +0 -4
- data/app/views/alchemy/ingredients/_html_view.html.erb +0 -1
- data/app/views/alchemy/ingredients/_link_view.html.erb +0 -4
- data/app/views/alchemy/ingredients/_node_view.html.erb +0 -1
- data/app/views/alchemy/ingredients/_page_view.html.erb +0 -1
- data/app/views/alchemy/ingredients/_picture_view.html.erb +0 -4
- data/app/views/alchemy/ingredients/_richtext_view.html.erb +0 -3
- data/app/views/alchemy/ingredients/_select_view.html.erb +0 -1
- data/app/views/alchemy/ingredients/_text_view.html.erb +0 -4
- data/app/views/alchemy/ingredients/_video_view.html.erb +0 -3
- data/babel.config.js +0 -12
- data/bin/importmap +0 -4
- data/bin/rails +0 -9
- data/bin/rspec +0 -3
- data/bin/setup +0 -30
- data/bin/start +0 -17
- data/bun.lockb +0 -0
- data/bundles/shoelace.js +0 -12
- data/bundles/tinymce.js +0 -22
- data/config/initializers/assets.rb +0 -4
- data/eslint.config.js +0 -17
- data/lib/alchemy/config.rb +0 -114
- data/lib/alchemy/element_definition.rb +0 -73
- data/lib/alchemy/page_layout.rb +0 -73
- data/lib/alchemy/resource_filter.rb +0 -40
- data/lib/alchemy/upgrader/seven_point_four.rb +0 -26
- data/lib/alchemy/upgrader/seven_point_three.rb +0 -52
- data/lib/alchemy/upgrader/tasks/.keep +0 -0
- data/lib/generators/alchemy/ingredient/templates/view.html.erb +0 -1
- data/lib/generators/alchemy/install/files/alchemy_admin.js +0 -1
- data/lib/generators/alchemy/install/files/all.js +0 -11
- data/lib/generators/alchemy/install/files/article.css +0 -25
- data/rollup.config.mjs +0 -108
- data/vendor/assets/images/remixicon.symbol.svg +0 -11
- /data/app/{assets/stylesheets → stylesheets}/alchemy/_fonts.scss +0 -0
- /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/attachment-select.scss +0 -0
- /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/flash.scss +0 -0
- /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/list_filter.scss +0 -0
- /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/spinner.scss +0 -0
- /data/app/{assets/stylesheets → stylesheets}/tinymce/skins/skintool.json +0 -0
- /data/app/{assets/stylesheets → stylesheets}/tinymce/skins/ui/alchemy/fonts/tinymce-mobile.woff +0 -0
@@ -1,27 +1,37 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
1
|
+
const JSON_CONTENT_TYPE = "application/json"
|
2
|
+
|
3
|
+
function isGetRequest(method) {
|
4
|
+
return method.toLowerCase() === "get"
|
5
|
+
}
|
6
|
+
|
7
|
+
function prepareURL(path, data, method) {
|
8
|
+
const url = new URL(window.location.origin + path)
|
9
|
+
|
10
|
+
if (data && isGetRequest(method)) {
|
11
|
+
url.search = new URLSearchParams(data).toString()
|
12
|
+
}
|
13
|
+
|
14
|
+
return url.toString()
|
15
|
+
}
|
16
|
+
|
17
|
+
function prepareHeaders(accept) {
|
18
|
+
return {
|
19
|
+
"Content-Type": "application/json; charset=utf-8",
|
20
|
+
Accept: accept,
|
21
|
+
"X-Requested-With": "XMLHttpRequest",
|
22
|
+
"X-CSRF-Token": getToken()
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
function prepareOptions(method, data, accept) {
|
27
|
+
const headers = prepareHeaders(accept)
|
28
|
+
const options = { method, headers }
|
29
|
+
|
30
|
+
if (data && !isGetRequest(method)) {
|
31
|
+
options.body = JSON.stringify(data)
|
32
|
+
}
|
33
|
+
|
34
|
+
return options
|
25
35
|
}
|
26
36
|
|
27
37
|
export function getToken() {
|
@@ -37,30 +47,27 @@ export function patch(url, data) {
|
|
37
47
|
return ajax("PATCH", url, data)
|
38
48
|
}
|
39
49
|
|
40
|
-
export function post(url, data, accept =
|
50
|
+
export function post(url, data, accept = JSON_CONTENT_TYPE) {
|
41
51
|
return ajax("POST", url, data, accept)
|
42
52
|
}
|
43
53
|
|
44
|
-
export default function ajax(
|
45
|
-
|
46
|
-
|
47
|
-
|
54
|
+
export default async function ajax(
|
55
|
+
method,
|
56
|
+
path,
|
57
|
+
data,
|
58
|
+
accept = JSON_CONTENT_TYPE
|
59
|
+
) {
|
60
|
+
const response = await fetch(
|
61
|
+
prepareURL(path, data, method),
|
62
|
+
prepareOptions(method, data, accept)
|
63
|
+
)
|
64
|
+
const contentType = response.headers.get("content-type")
|
65
|
+
const isJson = contentType?.includes(JSON_CONTENT_TYPE)
|
66
|
+
const responseData = isJson ? await response.json() : null
|
48
67
|
|
49
|
-
if (
|
50
|
-
|
51
|
-
}
|
52
|
-
|
53
|
-
xhr.open(method, url.toString())
|
54
|
-
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8")
|
55
|
-
xhr.setRequestHeader("Accept", accept)
|
56
|
-
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
|
57
|
-
xhr.setRequestHeader("X-CSRF-Token", getToken())
|
58
|
-
|
59
|
-
if (data && method.toLowerCase() !== "get") {
|
60
|
-
xhr.send(JSON.stringify(data))
|
68
|
+
if (response.ok) {
|
69
|
+
return { data: responseData, status: response.status }
|
61
70
|
} else {
|
62
|
-
|
71
|
+
throw responseData || new Error("An error occurred during the transaction")
|
63
72
|
}
|
64
|
-
|
65
|
-
return promise
|
66
73
|
}
|
@@ -20,10 +20,7 @@ import Sitemap from "alchemy_admin/sitemap"
|
|
20
20
|
import Spinner from "alchemy_admin/spinner"
|
21
21
|
import PagePublicationFields from "alchemy_admin/page_publication_fields"
|
22
22
|
import { reloadPreview } from "alchemy_admin/components/preview_window"
|
23
|
-
import {
|
24
|
-
openConfirmDialog,
|
25
|
-
confirmToDeleteDialog
|
26
|
-
} from "alchemy_admin/confirm_dialog"
|
23
|
+
import { openConfirmDialog } from "alchemy_admin/confirm_dialog"
|
27
24
|
|
28
25
|
// Web Components
|
29
26
|
import "alchemy_admin/components"
|
@@ -53,11 +50,9 @@ Object.assign(Alchemy, {
|
|
53
50
|
Sitemap,
|
54
51
|
Spinner,
|
55
52
|
PagePublicationFields,
|
56
|
-
reloadPreview
|
57
|
-
openConfirmDialog,
|
58
|
-
confirmToDeleteDialog
|
53
|
+
reloadPreview
|
59
54
|
})
|
60
55
|
|
61
56
|
Rails.start()
|
62
|
-
|
57
|
+
Turbo.config.forms.confirm = openConfirmDialog
|
63
58
|
$(document).on("turbo:load", Initializer)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module Admin
|
5
|
+
module Filters
|
6
|
+
class Base
|
7
|
+
attr_reader :name, :resource_name
|
8
|
+
|
9
|
+
def initialize(name:, resource_name:)
|
10
|
+
@name = name
|
11
|
+
@resource_name = resource_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def applied_filter_component(search_filter_params:, resource_url_proxy:, query:)
|
15
|
+
Alchemy::Admin::Resource::AppliedFilter.new(
|
16
|
+
link: dismiss_filter_url(search_filter_params, resource_url_proxy),
|
17
|
+
applied_filter_label: translated_name,
|
18
|
+
applied_filter_value: translated_value(search_filter_params[:q][name], query)
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def translated_name
|
25
|
+
Alchemy.t(:name, scope: [:filters, resource_name, name], default: name.to_s.humanize)
|
26
|
+
end
|
27
|
+
|
28
|
+
def dismiss_filter_url(search_filter_params, resource_url_proxy)
|
29
|
+
tmp_params = search_filter_params.dup
|
30
|
+
tmp_params[:q] = tmp_params[:q].except(name)
|
31
|
+
resource_url_proxy.url_for(
|
32
|
+
{action: "index"}.merge(tmp_params.except(:page))
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module Admin
|
5
|
+
module Filters
|
6
|
+
class Checkbox < Base
|
7
|
+
# Renders a checkbox filter input.
|
8
|
+
# @param [Hash] params The controller params.
|
9
|
+
# @param [Ransack::Search] _query The current search query.
|
10
|
+
# @return [Alchemy::Admin::FilterInputs::Checkbox] The checkbox filter input component.
|
11
|
+
def input_component(params, _query)
|
12
|
+
Alchemy::Admin::Resource::CheckboxFilter.new(name:, label: translated_name, params:)
|
13
|
+
end
|
14
|
+
|
15
|
+
def applied_filter_component(search_filter_params:, resource_url_proxy:, query:)
|
16
|
+
Alchemy::Admin::Resource::AppliedFilter.new(
|
17
|
+
link: dismiss_filter_url(search_filter_params, resource_url_proxy),
|
18
|
+
applied_filter_label: translated_name
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module Admin
|
5
|
+
module Filters
|
6
|
+
class Datepicker < Base
|
7
|
+
attr_reader :input_type
|
8
|
+
# Creates a resource filter that displays as a datepicker.
|
9
|
+
# @param name [String] The name of the filter.
|
10
|
+
# @param resource_name [String] The name of the resource.
|
11
|
+
# @param input_type [Symbol] The input type of the datepicker. Can be :date, :datetime, or :time.
|
12
|
+
# @example
|
13
|
+
# Alchemy::Admin::Filters::Datepicker.new(
|
14
|
+
# name: :created_at_lt,
|
15
|
+
# resource_name: :events,
|
16
|
+
# mode: :single,
|
17
|
+
# default: "2023-01-01"
|
18
|
+
def initialize(name:, resource_name:, input_type: :datetime)
|
19
|
+
super(name:, resource_name:)
|
20
|
+
@input_type = input_type
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns a datepicker filter component.
|
24
|
+
# @param params [Hash] The search filter params.
|
25
|
+
# @param query [Ransack::Search] The current search query.
|
26
|
+
# @return [Alchemy::Admin::Resource::DatepickerFilter] The datepicker filter component.
|
27
|
+
def input_component(params, _query)
|
28
|
+
Alchemy::Admin::Resource::DatepickerFilter.new(
|
29
|
+
name:,
|
30
|
+
label: translated_name,
|
31
|
+
input_type: @input_type,
|
32
|
+
params:
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def translated_value(value, query)
|
39
|
+
date = Time.zone.parse(value) if value.is_a?(String)
|
40
|
+
format = case input_type
|
41
|
+
when :date
|
42
|
+
::I18n.t(:default, scope: [:date, :formats, :alchemy])
|
43
|
+
when :datetime
|
44
|
+
::I18n.t(:default, scope: [:time, :formats, :alchemy])
|
45
|
+
when :time
|
46
|
+
::I18n.t(:time, scope: [:time, :formats, :alchemy])
|
47
|
+
end
|
48
|
+
::I18n.l(date, format: format)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module Admin
|
5
|
+
module Filters
|
6
|
+
class Select < Base
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
# Creates a resource filter that displays as a select.
|
10
|
+
# @param name [String] The name of the filter.
|
11
|
+
# @param resource_name [String] The name of the resource.
|
12
|
+
# @param options [Proc, Array] A proc that returns the options for the select, or an array of options.
|
13
|
+
def initialize(name:, resource_name:, options:)
|
14
|
+
super(name:, resource_name:)
|
15
|
+
@options = options_to_proc(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns a select filter component.
|
19
|
+
# @param params [Hash] The search filter params.
|
20
|
+
# @param query [Ransack::Search] The current search query.
|
21
|
+
# @return [ Alchemy::Admin::Resource::SelectFilter] The select filter component.
|
22
|
+
def input_component(params, query)
|
23
|
+
Alchemy::Admin::Resource::SelectFilter.new(
|
24
|
+
name:,
|
25
|
+
resource_name:,
|
26
|
+
label: translated_name,
|
27
|
+
include_blank:,
|
28
|
+
options: get_options_for_select(query),
|
29
|
+
params:
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def include_blank
|
36
|
+
Alchemy.t(:all, scope: [:filters, resource_name, name])
|
37
|
+
end
|
38
|
+
|
39
|
+
def options_to_proc(options)
|
40
|
+
if options.is_a? Proc
|
41
|
+
options
|
42
|
+
else
|
43
|
+
->(_query) { options }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_options_for_select(query)
|
48
|
+
options_for_select = options.call(query)
|
49
|
+
# The result of the query is an Array of Arrays, where the first element is the translated name and the second element is the value.
|
50
|
+
# If the first element is an Array, we assume that the options are already translated.
|
51
|
+
if options_for_select.first.is_a? Array
|
52
|
+
options_for_select
|
53
|
+
# If the values are translatable, we translate them.
|
54
|
+
elsif Alchemy.t(:values, scope: [:filters, resource_name, name])
|
55
|
+
options_for_select.map do |value|
|
56
|
+
[Alchemy.t(value.to_sym, scope: [:filters, resource_name, name, :values]), value]
|
57
|
+
end
|
58
|
+
# Otherwise we return the options as they are.
|
59
|
+
else
|
60
|
+
options_for_select.map { |option| [option, option] }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def translated_value(value, query)
|
65
|
+
get_options_for_select(query).detect { |option| option[1].to_s == value }&.first
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module Admin
|
5
|
+
module ResourceName
|
6
|
+
def resource_model_name
|
7
|
+
resource_array.join("/").classify
|
8
|
+
end
|
9
|
+
|
10
|
+
def resource_name
|
11
|
+
resources_name.singularize
|
12
|
+
end
|
13
|
+
|
14
|
+
def resource_array
|
15
|
+
controller_path_array.reject { |el| el == "admin" }
|
16
|
+
end
|
17
|
+
|
18
|
+
def resources_name
|
19
|
+
resource_array.last
|
20
|
+
end
|
21
|
+
|
22
|
+
def controller_path_array
|
23
|
+
controller_path.split("/")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -23,22 +23,16 @@ module Alchemy
|
|
23
23
|
include Alchemy::NameConversions
|
24
24
|
include Alchemy::Taggable
|
25
25
|
include Alchemy::TouchElements
|
26
|
+
include Alchemy::RelatableResource
|
26
27
|
|
27
|
-
|
28
|
-
after_assign { |f| write_attribute(:file_mime_type, f.mime_type) }
|
29
|
-
end
|
30
|
-
|
31
|
-
stampable stamper_class_name: Alchemy.user_class.name
|
28
|
+
include Alchemy.storage_adapter.attachment_class_methods
|
32
29
|
|
33
|
-
|
34
|
-
class_name: "Alchemy::Ingredients::File",
|
35
|
-
foreign_key: "related_object_id",
|
36
|
-
inverse_of: :related_object
|
30
|
+
stampable stamper_class_name: Alchemy.user_class_name
|
37
31
|
|
38
|
-
|
39
|
-
|
32
|
+
scope :by_file_type, ->(file_type) do
|
33
|
+
Alchemy.storage_adapter.by_file_type_scope(file_type)
|
34
|
+
end
|
40
35
|
|
41
|
-
scope :by_file_type, ->(file_type) { where(file_mime_type: file_type) }
|
42
36
|
scope :recent, -> { where("#{table_name}.created_at > ?", Time.current - 24.hours).order(:created_at) }
|
43
37
|
scope :without_tag, -> { left_outer_joins(:taggings).where(gutentag_taggings: {id: nil}) }
|
44
38
|
|
@@ -46,9 +40,8 @@ module Alchemy
|
|
46
40
|
class << self
|
47
41
|
# The class used to generate URLs for attachments
|
48
42
|
#
|
49
|
-
# @see Alchemy::Attachment::Url
|
50
43
|
def url_class
|
51
|
-
@_url_class ||= Alchemy
|
44
|
+
@_url_class ||= Alchemy.storage_adapter.attachment_url_class
|
52
45
|
end
|
53
46
|
|
54
47
|
# Set a different attachment url class
|
@@ -58,19 +51,6 @@ module Alchemy
|
|
58
51
|
@_url_class = klass
|
59
52
|
end
|
60
53
|
|
61
|
-
def alchemy_resource_filters
|
62
|
-
[
|
63
|
-
{
|
64
|
-
name: :by_file_type,
|
65
|
-
values: distinct.pluck(:file_mime_type).map { |type| [Alchemy.t(type, scope: "mime_types"), type] }.sort_by(&:first)
|
66
|
-
},
|
67
|
-
{
|
68
|
-
name: :misc,
|
69
|
-
values: %w[recent last_upload without_tag]
|
70
|
-
}
|
71
|
-
]
|
72
|
-
end
|
73
|
-
|
74
54
|
def last_upload
|
75
55
|
last_id = Attachment.maximum(:id)
|
76
56
|
return Attachment.all unless last_id
|
@@ -79,34 +59,43 @@ module Alchemy
|
|
79
59
|
end
|
80
60
|
|
81
61
|
def searchable_alchemy_resource_attributes
|
82
|
-
|
62
|
+
Alchemy.storage_adapter.searchable_alchemy_resource_attributes(name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def ransackable_attributes(_auth_object = nil)
|
66
|
+
Alchemy.storage_adapter.ransackable_attributes(name)
|
67
|
+
end
|
68
|
+
|
69
|
+
def ransackable_associations(_auth_object = nil)
|
70
|
+
Alchemy.storage_adapter.ransackable_associations(name)
|
71
|
+
end
|
72
|
+
|
73
|
+
def file_types(scope = all)
|
74
|
+
Alchemy.storage_adapter.file_formats(name, scope:)
|
83
75
|
end
|
84
76
|
|
85
77
|
def allowed_filetypes
|
86
|
-
|
78
|
+
Alchemy.config.uploader.allowed_filetypes.alchemy_attachments
|
79
|
+
end
|
80
|
+
|
81
|
+
def ransackable_scopes(_auth_object = nil)
|
82
|
+
%i[by_file_type recent last_upload without_tag deletable]
|
87
83
|
end
|
88
84
|
end
|
89
85
|
|
90
86
|
validates_presence_of :file
|
91
|
-
validates_size_of :file, maximum:
|
92
|
-
|
93
|
-
of: :file,
|
94
|
-
in: allowed_filetypes,
|
95
|
-
case_sensitive: false,
|
96
|
-
message: Alchemy.t("not a valid file"),
|
87
|
+
validates_size_of :file, maximum: Alchemy.config.uploader.file_size_limit.megabytes
|
88
|
+
validate :file_type_allowed,
|
97
89
|
unless: -> { self.class.allowed_filetypes.include?("*") }
|
98
90
|
|
99
|
-
before_save :
|
100
|
-
before_save :set_name, if: :file_name_changed?
|
91
|
+
before_save :set_name, if: -> { Alchemy.storage_adapter.set_attachment_name?(self) }
|
101
92
|
|
102
93
|
scope :with_file_type, ->(file_type) { where(file_mime_type: file_type) }
|
103
94
|
|
104
95
|
# Instance methods
|
105
96
|
|
106
97
|
def url(options = {})
|
107
|
-
|
108
|
-
self.class.url_class.new(self).call(options)
|
109
|
-
end
|
98
|
+
self.class.url_class.new(self).call(options)
|
110
99
|
end
|
111
100
|
|
112
101
|
# An url save filename without format suffix
|
@@ -119,9 +108,23 @@ module Alchemy
|
|
119
108
|
pages.any? && pages.not_restricted.blank?
|
120
109
|
end
|
121
110
|
|
111
|
+
# File name
|
112
|
+
def file_name
|
113
|
+
Alchemy.storage_adapter.file_name(self)
|
114
|
+
end
|
115
|
+
|
116
|
+
# File size
|
117
|
+
def file_size
|
118
|
+
Alchemy.storage_adapter.file_size(self)
|
119
|
+
end
|
120
|
+
|
121
|
+
def file_mime_type
|
122
|
+
Alchemy.storage_adapter.file_mime_type(self)
|
123
|
+
end
|
124
|
+
|
122
125
|
# File format suffix
|
123
126
|
def extension
|
124
|
-
|
127
|
+
Alchemy.storage_adapter.file_extension(self)
|
125
128
|
end
|
126
129
|
|
127
130
|
alias_method :suffix, :extension
|
@@ -157,12 +160,14 @@ module Alchemy
|
|
157
160
|
|
158
161
|
private
|
159
162
|
|
160
|
-
def
|
161
|
-
self.
|
163
|
+
def file_type_allowed
|
164
|
+
unless extension&.in?(self.class.allowed_filetypes)
|
165
|
+
errors.add(:file, Alchemy.t("not a valid file"))
|
166
|
+
end
|
162
167
|
end
|
163
168
|
|
164
169
|
def set_name
|
165
|
-
self.name
|
170
|
+
self.name ||= convert_to_humanized_name(file_name, extension)
|
166
171
|
end
|
167
172
|
end
|
168
173
|
end
|
@@ -53,16 +53,16 @@ module Alchemy
|
|
53
53
|
|
54
54
|
# Returns all element ingredient definitions from the +elements.yml+ file
|
55
55
|
def ingredient_definitions
|
56
|
-
definition.
|
56
|
+
definition.ingredients
|
57
57
|
end
|
58
58
|
|
59
59
|
# Returns the definition for given ingredient role
|
60
60
|
def ingredient_definition_for(role)
|
61
61
|
if ingredient_definitions.blank?
|
62
|
-
log_warning "Element #{name} is missing the ingredient definition for #{role}"
|
63
62
|
nil
|
64
63
|
else
|
65
|
-
ingredient_definitions.find {
|
64
|
+
ingredient_definitions.find { _1.role == role.to_s } ||
|
65
|
+
log_warning("Element #{name} is missing the ingredient definition for #{role}")
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -99,10 +99,10 @@ module Alchemy
|
|
99
99
|
|
100
100
|
# Builds ingredients for this element as described in the +elements.yml+
|
101
101
|
def build_ingredients
|
102
|
-
ingredient_definitions.each do |
|
102
|
+
ingredient_definitions.each do |definition|
|
103
103
|
ingredients.build(
|
104
|
-
role:
|
105
|
-
type: Alchemy::Ingredient.normalize_type(
|
104
|
+
role: definition.role,
|
105
|
+
type: Alchemy::Ingredient.normalize_type(definition.type)
|
106
106
|
)
|
107
107
|
end
|
108
108
|
end
|
@@ -33,7 +33,7 @@ module Alchemy
|
|
33
33
|
# @see Alchemy::Element::Presenters#display_name_for
|
34
34
|
#
|
35
35
|
def display_name
|
36
|
-
self.class.display_name_for(definition
|
36
|
+
self.class.display_name_for(definition.name || name)
|
37
37
|
end
|
38
38
|
|
39
39
|
# Returns a preview text for element.
|
@@ -78,15 +78,6 @@ module Alchemy
|
|
78
78
|
"#{display_name}: #{preview_text(maxlength)}"
|
79
79
|
end
|
80
80
|
|
81
|
-
# Returns a dom id used for elements html id tag.
|
82
|
-
# @deprecated
|
83
|
-
def dom_id
|
84
|
-
if caller.none? { |l| l =~ Regexp.new("alchemy/elements_block_helper.rb:117:in `element_view_for'") }
|
85
|
-
Alchemy::Deprecation.warn("dom_id is deprecated and will be removed from Alchemy 8.0. Please pass an id to the element_view_for helper instead.")
|
86
|
-
end
|
87
|
-
self.class.dom_id_class.new(self).call
|
88
|
-
end
|
89
|
-
|
90
81
|
# The ingredient that's used for element's preview text.
|
91
82
|
#
|
92
83
|
# It tries to find one of element's ingredients that is defined +as_element_title+.
|
@@ -113,8 +104,8 @@ module Alchemy
|
|
113
104
|
def first_ingredient_by_definition
|
114
105
|
return if ingredient_definitions.empty?
|
115
106
|
|
116
|
-
role = ingredient_definitions.first
|
117
|
-
ingredients.detect {
|
107
|
+
role = ingredient_definitions.first.role
|
108
|
+
ingredients.detect { _1.role == role }
|
118
109
|
end
|
119
110
|
end
|
120
111
|
end
|