alchemy_cms 7.4.6 → 8.0.0.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.
Potentially problematic release.
This version of alchemy_cms might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +86 -0
- data/Gemfile +13 -6
- data/README.md +13 -5
- data/alchemy_cms.gemspec +14 -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/custom-properties.css +1 -1
- 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/ui/alchemy/content.min.css +1 -0
- data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css +1 -1
- data/app/assets/config/alchemy_manifest.js +0 -2
- data/app/assets/images/alchemy/icons-sprite.svg +1 -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 +8 -15
- data/app/controllers/alchemy/admin/clipboard_controller.rb +2 -6
- data/app/controllers/alchemy/admin/elements_controller.rb +1 -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 +9 -5
- 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 +7 -2
- data/app/controllers/concerns/alchemy/admin/resource_filter.rb +92 -0
- data/app/decorators/alchemy/element_editor.rb +5 -48
- data/app/decorators/alchemy/ingredient_editor.rb +3 -53
- data/app/helpers/alchemy/admin/base_helper.rb +14 -84
- data/app/helpers/alchemy/admin/elements_helper.rb +4 -4
- 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/datepicker.js +10 -2
- data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +7 -7
- data/app/javascript/alchemy_admin/components/element_editor.js +1 -1
- data/app/javascript/alchemy_admin/components/index.js +1 -0
- data/app/javascript/alchemy_admin/components/remote_select.js +4 -1
- data/app/javascript/alchemy_admin/components/tags_autocomplete.js +5 -1
- data/app/javascript/alchemy_admin/components/tinymce.js +4 -2
- 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/dirty.js +3 -2
- data/app/javascript/alchemy_admin/i18n.js +15 -16
- data/app/javascript/alchemy_admin/initializer.js +1 -49
- data/app/javascript/alchemy_admin/utils/ajax.js +51 -44
- data/app/javascript/alchemy_admin.js +3 -8
- 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 +51 -34
- 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 +9 -27
- data/app/models/alchemy/element_definition.rb +160 -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 +0 -14
- 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_natures.rb +7 -7
- data/app/models/alchemy/page/page_scopes.rb +1 -1
- data/app/models/alchemy/page.rb +11 -33
- data/app/models/alchemy/page_definition.rb +115 -0
- data/app/models/alchemy/picture.rb +69 -79
- 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 +0 -15
- 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/{picture/url.rb → storage_adapter/dragonfly/picture_url.rb} +28 -12
- data/app/models/alchemy/{picture → storage_adapter/dragonfly}/preprocessor.rb +4 -4
- data/app/models/alchemy/storage_adapter/dragonfly.rb +183 -0
- data/app/models/alchemy/storage_adapter.rb +74 -0
- data/app/models/concerns/alchemy/picture_thumbnails.rb +19 -6
- data/app/serializers/alchemy/element_serializer.rb +0 -1
- data/app/services/alchemy/dragonfly_to_image_processing.rb +100 -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 +36 -49
- data/app/stylesheets/alchemy/_variables.scss +5 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/archive.scss +20 -37
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/base.scss +16 -14
- data/app/stylesheets/alchemy/admin/buttons.scss +160 -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 +23 -16
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/elements.scss +150 -105
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/errors.scss +5 -5
- data/app/stylesheets/alchemy/admin/filters.scss +58 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/flatpickr.scss +53 -60
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/form_fields.scss +21 -7
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/forms.scss +31 -19
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/frame.scss +20 -16
- data/app/stylesheets/alchemy/admin/hints.scss +5 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/icons.scss +10 -1
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/image_library.scss +10 -8
- 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 +61 -55
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/nodes.scss +21 -18
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/notices.scss +18 -18
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/page-select.scss +2 -2
- data/app/stylesheets/alchemy/admin/pagination.scss +144 -0
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/preview_window.scss +8 -6
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/print.scss +1 -1
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/resource_info.scss +8 -5
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/search.scss +9 -6
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/selects.scss +49 -37
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/shoelace.scss +5 -6
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/sitemap.scss +38 -33
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/tables.scss +6 -4
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/tags.scss +6 -4
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/toolbar.scss +12 -6
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/typography.scss +2 -2
- data/app/{assets/stylesheets → stylesheets}/alchemy/admin/upload.scss +7 -5
- data/app/stylesheets/alchemy/admin.scss +44 -0
- data/app/stylesheets/alchemy/custom-properties.css +244 -0
- data/app/stylesheets/alchemy/welcome.scss +75 -0
- data/app/{assets/stylesheets → stylesheets}/tinymce/skins/content/alchemy/content.scss +8 -9
- data/app/stylesheets/tinymce/skins/ui/alchemy/content.scss +1 -0
- data/app/{assets/stylesheets → stylesheets}/tinymce/skins/ui/alchemy/skin.scss +133 -136
- data/app/views/alchemy/admin/attachments/_files_list.html.erb +2 -2
- data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +1 -1
- 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/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 +1 -1
- data/app/views/alchemy/admin/elements/_header.html.erb +1 -0
- 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 +4 -7
- data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +2 -1
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/index.html.erb +2 -7
- data/app/views/alchemy/admin/resources/_applied_filters.html.erb +8 -0
- data/app/views/alchemy/admin/resources/_filter_bar.html.erb +11 -21
- 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/_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 +8 -0
- 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/redirect.js.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 +5 -9
- data/bun.lockb +0 -0
- data/bundles/remixicon.mjs +153 -0
- 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 +32 -14
- data/config/routes.rb +0 -2
- data/eslint.config.js +2 -1
- 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 +216 -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 +65 -17
- data/lib/alchemy/hints.rb +3 -7
- 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/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 +30 -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/shared_ingredient_examples.rb +5 -5
- data/lib/alchemy/upgrader/.keep +0 -0
- 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 +192 -170
- 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 +5 -14
- data/lib/generators/alchemy/install/templates/alchemy.rb.tt +196 -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/upgrade.rake +12 -47
- data/vendor/javascript/tinymce.min.js +1 -1
- data/vitest.config.js +21 -0
- metadata +181 -180
- 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.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/buttons.scss +0 -124
- 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.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/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/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/config/initializers/assets.rb +0 -4
- 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/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/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/attachments.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/node-select.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
@@ -21,6 +21,21 @@ module Alchemy
|
|
21
21
|
searchable_alchemy_resource_associations
|
22
22
|
end
|
23
23
|
|
24
|
+
# Allow all scopes used in resource filters to be used with Ransack
|
25
|
+
def ransackable_scopes(_auth_object = nil)
|
26
|
+
if respond_to?(:alchemy_resource_filters)
|
27
|
+
alchemy_resource_filters.flat_map do |filter_set|
|
28
|
+
if respond_to?(filter_set[:name])
|
29
|
+
filter_set[:name].to_s
|
30
|
+
else
|
31
|
+
filter_set[:values].map(&:to_s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
[]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
24
39
|
protected
|
25
40
|
|
26
41
|
def searchable_alchemy_resource_attributes
|
@@ -41,8 +41,8 @@ module Alchemy
|
|
41
41
|
#
|
42
42
|
def page_layout_names(layoutpages: false)
|
43
43
|
page_layout_definitions.select do |layout|
|
44
|
-
!!layout
|
45
|
-
end.
|
44
|
+
!!layout.layoutpage && layoutpages || !layout.layoutpage && !layoutpages
|
45
|
+
end.tap { _1.collect!(&:name) }
|
46
46
|
end
|
47
47
|
|
48
48
|
# Returns sites page layout definitions
|
@@ -51,11 +51,11 @@ module Alchemy
|
|
51
51
|
#
|
52
52
|
def page_layout_definitions
|
53
53
|
if definition["page_layouts"].presence
|
54
|
-
Alchemy::
|
55
|
-
layout
|
54
|
+
Alchemy::PageDefinition.all.select do |layout|
|
55
|
+
layout.name.in?(definition["page_layouts"])
|
56
56
|
end
|
57
57
|
else
|
58
|
-
Alchemy::
|
58
|
+
Alchemy::PageDefinition.all
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
data/app/models/alchemy/site.rb
CHANGED
@@ -57,21 +57,6 @@ module Alchemy
|
|
57
57
|
end
|
58
58
|
|
59
59
|
class << self
|
60
|
-
# @deprecated Use {Alchemy::Current#site=} instead.
|
61
|
-
def current=(site)
|
62
|
-
Current.site = site
|
63
|
-
end
|
64
|
-
deprecate "current=": :"Alchemy::Current.site=", deprecator: Alchemy::Deprecation
|
65
|
-
|
66
|
-
# @deprecated Use {Alchemy::Current#site} instead.
|
67
|
-
def current
|
68
|
-
Current.site
|
69
|
-
end
|
70
|
-
deprecate current: :"Alchemy::Current.site", deprecator: Alchemy::Deprecation
|
71
|
-
|
72
|
-
alias_method :default, :first
|
73
|
-
deprecate default: :first, deprecator: Alchemy::Deprecation
|
74
|
-
|
75
60
|
def find_for_host(host)
|
76
61
|
# These are split up into two separate queries in order to run the
|
77
62
|
# fastest query first (selecting the domain by its primary host name).
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
class StorageAdapter
|
5
|
+
# The class representing an URL to an ActiveStorage attachment
|
6
|
+
#
|
7
|
+
class ActiveStorage::AttachmentUrl
|
8
|
+
attr_reader :attachment
|
9
|
+
|
10
|
+
def initialize(attachment)
|
11
|
+
@attachment = attachment
|
12
|
+
end
|
13
|
+
|
14
|
+
# The attachment url
|
15
|
+
#
|
16
|
+
# @param [Hash] options
|
17
|
+
# @option options [Symbol] :download return a URL for downloading the attachment
|
18
|
+
# @option options [Symbol] :name The filename
|
19
|
+
# @option options [Symbol] :format The file extension
|
20
|
+
#
|
21
|
+
# @return [String]
|
22
|
+
#
|
23
|
+
def call(options = {})
|
24
|
+
if attachment.file.attached?
|
25
|
+
options[:format] ||= attachment.suffix
|
26
|
+
if options.delete(:download)
|
27
|
+
routes.download_attachment_path(attachment, options)
|
28
|
+
else
|
29
|
+
routes.show_attachment_path(attachment, options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def routes
|
37
|
+
Alchemy::Engine.routes.url_helpers
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
class StorageAdapter
|
5
|
+
# Returns the URL to a variant of a picture using ActiveStorage
|
6
|
+
class ActiveStorage::PictureUrl
|
7
|
+
attr_reader :picture, :image_file
|
8
|
+
|
9
|
+
# @param [Alchemy::Picture]
|
10
|
+
#
|
11
|
+
def initialize(picture)
|
12
|
+
@picture = picture
|
13
|
+
@image_file = picture.image_file
|
14
|
+
end
|
15
|
+
|
16
|
+
# The URL to a variant of a picture
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
#
|
20
|
+
def call(options = {})
|
21
|
+
variant_options = DragonflyToImageProcessing.call(options)
|
22
|
+
variant_options[:format] = options[:format] || default_output_format
|
23
|
+
variant = image_file&.variant(variant_options)
|
24
|
+
return unless variant
|
25
|
+
|
26
|
+
Rails.application.routes.url_helpers.rails_blob_path(
|
27
|
+
variant,
|
28
|
+
{
|
29
|
+
filename: filename(options),
|
30
|
+
format: variant_options[:format],
|
31
|
+
only_path: true
|
32
|
+
}
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def filename(options = {})
|
39
|
+
if picture.name.presence
|
40
|
+
picture.name.to_param
|
41
|
+
else
|
42
|
+
picture.image_file_name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def default_output_format
|
47
|
+
if Alchemy.config.image_output_format == "original"
|
48
|
+
picture.image_file_extension
|
49
|
+
else
|
50
|
+
Alchemy.config.image_output_format
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
class StorageAdapter
|
5
|
+
class ActiveStorage::Preprocessor
|
6
|
+
def initialize(attachable)
|
7
|
+
@attachable = attachable
|
8
|
+
end
|
9
|
+
|
10
|
+
# Preprocess images after upload
|
11
|
+
#
|
12
|
+
# Define preprocessing options in the Alchemy.config
|
13
|
+
#
|
14
|
+
# preprocess_image_resize [String] - Downsizing example: '1000x1000>'
|
15
|
+
#
|
16
|
+
def call
|
17
|
+
max_image_size = Alchemy.config.get(:preprocess_image_resize)
|
18
|
+
if max_image_size.present?
|
19
|
+
self.class.process_thumb(attachable, size: max_image_size)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :attachable
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def generate_thumbs!(attachable)
|
27
|
+
Alchemy::Picture::THUMBNAIL_SIZES.values.each do |size|
|
28
|
+
process_thumb(attachable, size: size, flatten: true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def process_thumb(attachable, options = {})
|
33
|
+
attachable.variant :thumb,
|
34
|
+
**Alchemy::DragonflyToImageProcessing.call(options),
|
35
|
+
preprocessed: true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module Alchemy
|
2
|
+
class StorageAdapter
|
3
|
+
module ActiveStorage
|
4
|
+
module PictureClassMethods
|
5
|
+
def self.included(base)
|
6
|
+
base.has_one_attached :image_file do |attachable|
|
7
|
+
# Only works in Rails 7.1+
|
8
|
+
# https://github.com/rails/rails/pull/47473
|
9
|
+
Alchemy.storage_adapter.preprocessor_class.new(attachable).call
|
10
|
+
Alchemy.storage_adapter.preprocessor_class.generate_thumbs!(attachable)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module AttachmentClassMethods
|
16
|
+
def self.included(base)
|
17
|
+
base.has_one_attached :file
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
extend self
|
22
|
+
|
23
|
+
def attachment_url_class
|
24
|
+
AttachmentUrl
|
25
|
+
end
|
26
|
+
|
27
|
+
def preprocessor_class
|
28
|
+
Preprocessor
|
29
|
+
end
|
30
|
+
|
31
|
+
def picture_url_class
|
32
|
+
PictureUrl
|
33
|
+
end
|
34
|
+
|
35
|
+
def file_formats(class_name, scope:)
|
36
|
+
attachment_scope = case class_name
|
37
|
+
when "Alchemy::Attachment" then scope.with_attached_file
|
38
|
+
when "Alchemy::Picture" then scope.with_attached_image_file
|
39
|
+
end
|
40
|
+
|
41
|
+
attachment_scope.pluck("active_storage_blobs.content_type").uniq.tap(&:compact!).presence || []
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [String]
|
45
|
+
# @return [Array<String>]
|
46
|
+
def searchable_alchemy_resource_attributes(class_name)
|
47
|
+
case class_name
|
48
|
+
when "Alchemy::Attachment"
|
49
|
+
%w[name file_blob_filename]
|
50
|
+
when "Alchemy::Picture"
|
51
|
+
%w[name image_file_blob_filename]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param [String]
|
56
|
+
# @return [Array<String>]
|
57
|
+
def ransackable_attributes(_class_name)
|
58
|
+
%w[name]
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param [String]
|
62
|
+
# @return [Array<String>]
|
63
|
+
def ransackable_associations(class_name)
|
64
|
+
case class_name
|
65
|
+
when "Alchemy::Attachment"
|
66
|
+
%w[file_blob]
|
67
|
+
when "Alchemy::Picture"
|
68
|
+
%w[image_file_blob]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def rescuable_errors
|
73
|
+
::ActiveStorage::Error
|
74
|
+
end
|
75
|
+
|
76
|
+
# @param [String]
|
77
|
+
# @return [Alchemy::Picture::ActiveRecord_Relation]
|
78
|
+
def by_file_format_scope(file_format)
|
79
|
+
Picture.with_attached_image_file.joins(:image_file_blob).where(active_storage_blobs: {content_type: file_format})
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param [String]
|
83
|
+
# @return [Alchemy::Atachment::ActiveRecord_Relation]
|
84
|
+
def by_file_type_scope(file_type)
|
85
|
+
Attachment.with_attached_file.joins(:file_blob).where(active_storage_blobs: {content_type: file_type})
|
86
|
+
end
|
87
|
+
|
88
|
+
# @param [Alchemy::Attachment]
|
89
|
+
# @return [String]
|
90
|
+
def file_name(attachment)
|
91
|
+
attachment.file&.filename&.to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
# @param [Alchemy::Attachment]
|
95
|
+
# @return [Integer]
|
96
|
+
def file_size(attachment)
|
97
|
+
attachment.file&.byte_size
|
98
|
+
end
|
99
|
+
|
100
|
+
# @param [Alchemy::Attachment]
|
101
|
+
# @return [String]
|
102
|
+
def file_mime_type(attachment)
|
103
|
+
attachment.file&.content_type
|
104
|
+
end
|
105
|
+
|
106
|
+
# @param [Alchemy::Attachment]
|
107
|
+
# @return [String]
|
108
|
+
def file_extension(attachment)
|
109
|
+
attachment.file&.filename&.extension
|
110
|
+
end
|
111
|
+
|
112
|
+
# @param [Alchemy::Picture]
|
113
|
+
# @return [TrueClass, FalseClass]
|
114
|
+
def has_convertible_format?(picture)
|
115
|
+
picture.image_file&.variable?
|
116
|
+
end
|
117
|
+
|
118
|
+
# @param [Alchemy::Picture]
|
119
|
+
# @return [String]
|
120
|
+
def image_file_name(picture)
|
121
|
+
picture.image_file&.filename&.to_s
|
122
|
+
end
|
123
|
+
|
124
|
+
# @param [Alchemy::Picture]
|
125
|
+
# @return [String]
|
126
|
+
def image_file_format(picture)
|
127
|
+
picture.image_file&.content_type
|
128
|
+
end
|
129
|
+
|
130
|
+
# @param [Alchemy::Picture]
|
131
|
+
# @return [Integer]
|
132
|
+
def image_file_size(picture)
|
133
|
+
picture.image_file&.byte_size
|
134
|
+
end
|
135
|
+
|
136
|
+
# @param [Alchemy::Picture]
|
137
|
+
# @return [Integer]
|
138
|
+
def image_file_width(picture)
|
139
|
+
picture.image_file&.metadata&.fetch(:width, nil)
|
140
|
+
end
|
141
|
+
|
142
|
+
# @param [Alchemy::Picture]
|
143
|
+
# @return [Integer]
|
144
|
+
def image_file_height(picture)
|
145
|
+
picture.image_file&.metadata&.fetch(:height, nil)
|
146
|
+
end
|
147
|
+
|
148
|
+
# @param [Alchemy::Picture]
|
149
|
+
# @return [Integer]
|
150
|
+
def image_file_extension(picture)
|
151
|
+
picture.image_file&.filename&.extension&.downcase
|
152
|
+
end
|
153
|
+
|
154
|
+
# @param [Alchemy::Picture]
|
155
|
+
# @return [TrueClass, FalseClass]
|
156
|
+
def image_file_present?(picture)
|
157
|
+
picture.image_file.attached?
|
158
|
+
end
|
159
|
+
|
160
|
+
# @param Alchemy::Picture::ActiveRecord_Relation
|
161
|
+
# @return Alchemy::Picture::ActiveRecord_Relation
|
162
|
+
def preloaded_pictures(pictures)
|
163
|
+
pictures.with_attached_image_file
|
164
|
+
end
|
165
|
+
|
166
|
+
# @param [Alchemy::Attachment]
|
167
|
+
# @return [TrueClass, FalseClass]
|
168
|
+
def set_attachment_name?(attachment)
|
169
|
+
attachment.file.changed?
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -1,14 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Alchemy
|
4
|
-
class
|
5
|
-
# The class representing an URL to an attachment
|
4
|
+
class StorageAdapter
|
5
|
+
# The class representing an URL to an Dragonfly attachment
|
6
6
|
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
#
|
11
|
-
class Url
|
7
|
+
class Dragonfly::AttachmentUrl
|
8
|
+
attr_reader :attachment
|
9
|
+
|
12
10
|
def initialize(attachment)
|
13
11
|
@attachment = attachment
|
14
12
|
end
|
@@ -23,11 +21,13 @@ module Alchemy
|
|
23
21
|
# @return [String]
|
24
22
|
#
|
25
23
|
def call(options = {})
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
if attachment.file
|
25
|
+
options[:format] ||= attachment.suffix
|
26
|
+
if options.delete(:download)
|
27
|
+
routes.download_attachment_path(attachment, options)
|
28
|
+
else
|
29
|
+
routes.show_attachment_path(attachment, options)
|
30
|
+
end
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -1,23 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Alchemy
|
4
|
-
class
|
5
|
-
class
|
6
|
-
|
4
|
+
class StorageAdapter
|
5
|
+
class Dragonfly::PictureUrl
|
6
|
+
TRANSFORMATION_OPTIONS = [
|
7
|
+
:crop,
|
8
|
+
:crop_from,
|
9
|
+
:crop_size,
|
10
|
+
:flatten,
|
11
|
+
:format,
|
12
|
+
:quality,
|
13
|
+
:size,
|
14
|
+
:upsample
|
15
|
+
]
|
7
16
|
|
8
|
-
|
9
|
-
#
|
10
|
-
def initialize(variant)
|
11
|
-
raise ArgumentError, "Variant missing!" if variant.nil?
|
17
|
+
attr_reader :picture, :variant, :thumb
|
12
18
|
|
13
|
-
|
19
|
+
# @param [Alchemy::Picture]
|
20
|
+
#
|
21
|
+
def initialize(picture)
|
22
|
+
@picture = picture
|
14
23
|
end
|
15
24
|
|
16
25
|
# The URL to a variant of a picture
|
17
26
|
#
|
18
27
|
# @return [String]
|
19
28
|
#
|
20
|
-
def call(
|
29
|
+
def call(options = {})
|
30
|
+
@variant = PictureVariant.new(picture, options.slice(*TRANSFORMATION_OPTIONS))
|
31
|
+
params = {
|
32
|
+
basename: picture.name,
|
33
|
+
ext: variant.render_format,
|
34
|
+
name: picture.name
|
35
|
+
}
|
36
|
+
|
21
37
|
return variant.image.url(params) unless processible_image?
|
22
38
|
|
23
39
|
"/#{uid}"
|
@@ -43,10 +59,10 @@ module Alchemy
|
|
43
59
|
end
|
44
60
|
|
45
61
|
def find_thumb_by(signature)
|
46
|
-
@thumb = if
|
47
|
-
|
62
|
+
@thumb = if picture.thumbs.loaded?
|
63
|
+
picture.thumbs.find { |t| t.signature == signature }
|
48
64
|
else
|
49
|
-
|
65
|
+
picture.thumbs.find_by(signature: signature)
|
50
66
|
end
|
51
67
|
end
|
52
68
|
end
|
@@ -1,20 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Alchemy
|
4
|
-
class
|
5
|
-
class Preprocessor
|
4
|
+
class StorageAdapter
|
5
|
+
class Dragonfly::Preprocessor
|
6
6
|
def initialize(image_file)
|
7
7
|
@image_file = image_file
|
8
8
|
end
|
9
9
|
|
10
10
|
# Preprocess images after upload
|
11
11
|
#
|
12
|
-
# Define preprocessing options in the Alchemy
|
12
|
+
# Define preprocessing options in the Alchemy.config
|
13
13
|
#
|
14
14
|
# preprocess_image_resize [String] - Downsizing example: '1000x1000>'
|
15
15
|
#
|
16
16
|
def call
|
17
|
-
max_image_size = Alchemy
|
17
|
+
max_image_size = Alchemy.config.preprocess_image_resize
|
18
18
|
image_file.thumb!(max_image_size) if max_image_size.present?
|
19
19
|
# Auto orient the image so EXIF orientation data is taken into account
|
20
20
|
image_file.auto_orient!
|
@@ -0,0 +1,183 @@
|
|
1
|
+
module Alchemy
|
2
|
+
class StorageAdapter
|
3
|
+
module Dragonfly
|
4
|
+
module PictureClassMethods
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
dragonfly_accessor :image_file, app: :alchemy_pictures do
|
8
|
+
# Preprocess after uploading the picture
|
9
|
+
after_assign do |image|
|
10
|
+
if has_convertible_format?
|
11
|
+
Alchemy.storage_adapter.preprocessor_class.new(image).call
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
has_many :thumbs, class_name: "Alchemy::PictureThumb", dependent: :destroy
|
17
|
+
|
18
|
+
# Create important thumbnails upfront
|
19
|
+
after_create -> { PictureThumb.generate_thumbs!(self) },
|
20
|
+
if: :has_convertible_format?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module AttachmentClassMethods
|
26
|
+
def self.included(base)
|
27
|
+
base.class_eval do
|
28
|
+
dragonfly_accessor :file, app: :alchemy_attachments do
|
29
|
+
after_assign { |file|
|
30
|
+
write_attribute(:file_mime_type, file.mime_type)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
extend self
|
38
|
+
|
39
|
+
CONVERTIBLE_FILE_FORMATS = %w[gif jpg jpeg png webp].freeze
|
40
|
+
|
41
|
+
def attachment_url_class
|
42
|
+
AttachmentUrl
|
43
|
+
end
|
44
|
+
|
45
|
+
def preprocessor_class
|
46
|
+
Preprocessor
|
47
|
+
end
|
48
|
+
|
49
|
+
def picture_url_class
|
50
|
+
PictureUrl
|
51
|
+
end
|
52
|
+
|
53
|
+
def file_formats(class_name, scope:)
|
54
|
+
mime_type_column = case class_name
|
55
|
+
when "Alchemy::Attachment" then :file_mime_type
|
56
|
+
when "Alchemy::Picture" then :image_file_format
|
57
|
+
end
|
58
|
+
|
59
|
+
scope.reorder(mime_type_column).distinct.pluck(mime_type_column).compact.presence || []
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param [String]
|
63
|
+
# @return [Array<String>]
|
64
|
+
def searchable_alchemy_resource_attributes(class_name)
|
65
|
+
case class_name
|
66
|
+
when "Alchemy::Attachment"
|
67
|
+
%w[name file_name]
|
68
|
+
when "Alchemy::Picture"
|
69
|
+
%w[name image_file_name]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
alias_method :ransackable_attributes, :searchable_alchemy_resource_attributes
|
73
|
+
|
74
|
+
# @param [String]
|
75
|
+
# @return [Array<String>]
|
76
|
+
def ransackable_associations(_class_name)
|
77
|
+
%w[]
|
78
|
+
end
|
79
|
+
|
80
|
+
def rescuable_errors
|
81
|
+
::Dragonfly::Job::Fetch::NotFound
|
82
|
+
end
|
83
|
+
|
84
|
+
# @param [String]
|
85
|
+
# @return [Alchemy::Picture::ActiveRecord_Relation]
|
86
|
+
def by_file_format_scope(file_format)
|
87
|
+
Picture.where(image_file_format: file_format)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param [String]
|
91
|
+
# @return [Alchemy::Attachment::ActiveRecord_Relation]
|
92
|
+
def by_file_type_scope(file_type)
|
93
|
+
Attachment.where(file_mime_type: file_type)
|
94
|
+
end
|
95
|
+
|
96
|
+
# @param [Alchemy::Attachment]
|
97
|
+
# @return [String]
|
98
|
+
def file_name(attachment)
|
99
|
+
attachment.read_attribute(:file_name)
|
100
|
+
end
|
101
|
+
|
102
|
+
# @param [Alchemy::Attachment]
|
103
|
+
# @return [Integer]
|
104
|
+
def file_size(attachment)
|
105
|
+
attachment.read_attribute(:file_size)
|
106
|
+
end
|
107
|
+
|
108
|
+
# @param [Alchemy::Attachment]
|
109
|
+
# @return [String]
|
110
|
+
def file_mime_type(attachment)
|
111
|
+
attachment.read_attribute(:file_mime_type)
|
112
|
+
end
|
113
|
+
|
114
|
+
# @param [Alchemy::Attachment]
|
115
|
+
# @return [String]
|
116
|
+
def file_extension(attachment)
|
117
|
+
content_type = file_mime_type(attachment)
|
118
|
+
Marcel::Magic.new(content_type).extensions.first if content_type
|
119
|
+
end
|
120
|
+
|
121
|
+
# @param [Alchemy::Picture]
|
122
|
+
# @return [TrueClass, FalseClass]
|
123
|
+
def has_convertible_format?(picture)
|
124
|
+
image_file_extension(picture).in?(CONVERTIBLE_FILE_FORMATS)
|
125
|
+
end
|
126
|
+
|
127
|
+
# @param [Alchemy::Picture]
|
128
|
+
# @return [String]
|
129
|
+
def image_file_name(picture)
|
130
|
+
picture.read_attribute(:image_file_name)
|
131
|
+
end
|
132
|
+
|
133
|
+
# @param [Alchemy::Picture]
|
134
|
+
# @return [String]
|
135
|
+
def image_file_format(picture)
|
136
|
+
ext = picture.read_attribute(:image_file_format)
|
137
|
+
Marcel::MimeType.for(extension: ext) if ext
|
138
|
+
end
|
139
|
+
|
140
|
+
# @param [Alchemy::Picture]
|
141
|
+
# @return [Integer]
|
142
|
+
def image_file_size(picture)
|
143
|
+
picture.read_attribute(:image_file_size)
|
144
|
+
end
|
145
|
+
|
146
|
+
# @param [Alchemy::Picture]
|
147
|
+
# @return [Integer]
|
148
|
+
def image_file_width(picture)
|
149
|
+
picture.read_attribute(:image_file_width)
|
150
|
+
end
|
151
|
+
|
152
|
+
# @param [Alchemy::Picture]
|
153
|
+
# @return [Integer]
|
154
|
+
def image_file_height(picture)
|
155
|
+
picture.read_attribute(:image_file_height)
|
156
|
+
end
|
157
|
+
|
158
|
+
# @param [Alchemy::Picture]
|
159
|
+
# @return [String]
|
160
|
+
def image_file_extension(picture)
|
161
|
+
picture.read_attribute(:image_file_format)
|
162
|
+
end
|
163
|
+
|
164
|
+
# @param [Alchemy::Picture]
|
165
|
+
# @return [TrueClass, FalseClass]
|
166
|
+
def image_file_present?(picture)
|
167
|
+
!!picture.image_file
|
168
|
+
end
|
169
|
+
|
170
|
+
# @param Alchemy::Picture::ActiveRecord_Relation
|
171
|
+
# @return Alchemy::Picture::ActiveRecord_Relation
|
172
|
+
def preloaded_pictures(pictures)
|
173
|
+
pictures.includes(:thumbs)
|
174
|
+
end
|
175
|
+
|
176
|
+
# @param [Alchemy::Attachment]
|
177
|
+
# @return [TrueClass, FalseClass]
|
178
|
+
def set_attachment_name?(attachment)
|
179
|
+
attachment.file_name_changed?
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|