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
@@ -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
|
@@ -24,11 +24,9 @@ module Alchemy
|
|
24
24
|
include Alchemy::Taggable
|
25
25
|
include Alchemy::TouchElements
|
26
26
|
|
27
|
-
|
28
|
-
after_assign { |f| write_attribute(:file_mime_type, f.mime_type) }
|
29
|
-
end
|
27
|
+
include Alchemy.storage_adapter.attachment_class_methods
|
30
28
|
|
31
|
-
stampable stamper_class_name: Alchemy.
|
29
|
+
stampable stamper_class_name: Alchemy.user_class_name
|
32
30
|
|
33
31
|
has_many :file_ingredients,
|
34
32
|
class_name: "Alchemy::Ingredients::File",
|
@@ -38,7 +36,10 @@ module Alchemy
|
|
38
36
|
has_many :elements, through: :file_ingredients
|
39
37
|
has_many :pages, through: :elements
|
40
38
|
|
41
|
-
scope :by_file_type, ->(file_type)
|
39
|
+
scope :by_file_type, ->(file_type) do
|
40
|
+
Alchemy.storage_adapter.by_file_type_scope(file_type)
|
41
|
+
end
|
42
|
+
|
42
43
|
scope :recent, -> { where("#{table_name}.created_at > ?", Time.current - 24.hours).order(:created_at) }
|
43
44
|
scope :without_tag, -> { left_outer_joins(:taggings).where(gutentag_taggings: {id: nil}) }
|
44
45
|
|
@@ -46,9 +47,8 @@ module Alchemy
|
|
46
47
|
class << self
|
47
48
|
# The class used to generate URLs for attachments
|
48
49
|
#
|
49
|
-
# @see Alchemy::Attachment::Url
|
50
50
|
def url_class
|
51
|
-
@_url_class ||= Alchemy
|
51
|
+
@_url_class ||= Alchemy.storage_adapter.attachment_url_class
|
52
52
|
end
|
53
53
|
|
54
54
|
# Set a different attachment url class
|
@@ -58,19 +58,6 @@ module Alchemy
|
|
58
58
|
@_url_class = klass
|
59
59
|
end
|
60
60
|
|
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
61
|
def last_upload
|
75
62
|
last_id = Attachment.maximum(:id)
|
76
63
|
return Attachment.all unless last_id
|
@@ -79,33 +66,43 @@ module Alchemy
|
|
79
66
|
end
|
80
67
|
|
81
68
|
def searchable_alchemy_resource_attributes
|
82
|
-
|
69
|
+
Alchemy.storage_adapter.searchable_alchemy_resource_attributes(name)
|
70
|
+
end
|
71
|
+
|
72
|
+
def ransackable_attributes(_auth_object = nil)
|
73
|
+
Alchemy.storage_adapter.ransackable_attributes(name)
|
74
|
+
end
|
75
|
+
|
76
|
+
def ransackable_associations(_auth_object = nil)
|
77
|
+
Alchemy.storage_adapter.ransackable_associations(name)
|
78
|
+
end
|
79
|
+
|
80
|
+
def file_types(scope = all)
|
81
|
+
Alchemy.storage_adapter.file_formats(name, scope:)
|
83
82
|
end
|
84
83
|
|
85
84
|
def allowed_filetypes
|
86
|
-
|
85
|
+
Alchemy.config.uploader.allowed_filetypes.alchemy_attachments
|
86
|
+
end
|
87
|
+
|
88
|
+
def ransackable_scopes(_auth_object = nil)
|
89
|
+
%i[by_file_type recent last_upload without_tag]
|
87
90
|
end
|
88
91
|
end
|
89
92
|
|
90
93
|
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"),
|
94
|
+
validates_size_of :file, maximum: Alchemy.config.uploader.file_size_limit.megabytes
|
95
|
+
validate :file_type_allowed,
|
97
96
|
unless: -> { self.class.allowed_filetypes.include?("*") }
|
98
97
|
|
99
|
-
before_save :set_name, if:
|
98
|
+
before_save :set_name, if: -> { Alchemy.storage_adapter.set_attachment_name?(self) }
|
100
99
|
|
101
100
|
scope :with_file_type, ->(file_type) { where(file_mime_type: file_type) }
|
102
101
|
|
103
102
|
# Instance methods
|
104
103
|
|
105
104
|
def url(options = {})
|
106
|
-
|
107
|
-
self.class.url_class.new(self).call(options)
|
108
|
-
end
|
105
|
+
self.class.url_class.new(self).call(options)
|
109
106
|
end
|
110
107
|
|
111
108
|
# An url save filename without format suffix
|
@@ -118,9 +115,23 @@ module Alchemy
|
|
118
115
|
pages.any? && pages.not_restricted.blank?
|
119
116
|
end
|
120
117
|
|
118
|
+
# File name
|
119
|
+
def file_name
|
120
|
+
Alchemy.storage_adapter.file_name(self)
|
121
|
+
end
|
122
|
+
|
123
|
+
# File size
|
124
|
+
def file_size
|
125
|
+
Alchemy.storage_adapter.file_size(self)
|
126
|
+
end
|
127
|
+
|
128
|
+
def file_mime_type
|
129
|
+
Alchemy.storage_adapter.file_mime_type(self)
|
130
|
+
end
|
131
|
+
|
121
132
|
# File format suffix
|
122
133
|
def extension
|
123
|
-
|
134
|
+
Alchemy.storage_adapter.file_extension(self)
|
124
135
|
end
|
125
136
|
|
126
137
|
alias_method :suffix, :extension
|
@@ -156,8 +167,14 @@ module Alchemy
|
|
156
167
|
|
157
168
|
private
|
158
169
|
|
170
|
+
def file_type_allowed
|
171
|
+
unless extension&.in?(self.class.allowed_filetypes)
|
172
|
+
errors.add(:file, Alchemy.t("not a valid file"))
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
159
176
|
def set_name
|
160
|
-
self.name
|
177
|
+
self.name ||= convert_to_humanized_name(file_name, extension)
|
161
178
|
end
|
162
179
|
end
|
163
180
|
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
|
@@ -30,7 +30,6 @@ module Alchemy
|
|
30
30
|
|
31
31
|
include Alchemy::Logger
|
32
32
|
include Alchemy::Taggable
|
33
|
-
include Alchemy::Hints
|
34
33
|
|
35
34
|
FORBIDDEN_DEFINITION_ATTRIBUTES = [
|
36
35
|
"amount",
|
@@ -55,7 +54,7 @@ module Alchemy
|
|
55
54
|
#
|
56
55
|
acts_as_list scope: [:page_version_id, :fixed, :parent_element_id]
|
57
56
|
|
58
|
-
stampable stamper_class_name: Alchemy.
|
57
|
+
stampable stamper_class_name: Alchemy.user_class_name
|
59
58
|
|
60
59
|
before_destroy :delete_all_nested_elements
|
61
60
|
|
@@ -107,6 +106,7 @@ module Alchemy
|
|
107
106
|
scope :not_nested, -> { where(parent_element_id: nil) }
|
108
107
|
|
109
108
|
delegate :restricted?, to: :page, allow_nil: true
|
109
|
+
delegate :deprecation_notice, :has_hint?, :hint, to: :definition
|
110
110
|
|
111
111
|
# Concerns
|
112
112
|
include Definitions
|
@@ -131,27 +131,9 @@ module Alchemy
|
|
131
131
|
raise(ElementDefinitionError, attributes)
|
132
132
|
end
|
133
133
|
|
134
|
-
super(element_definition.merge(element_attributes).except(*FORBIDDEN_DEFINITION_ATTRIBUTES))
|
134
|
+
super(element_definition.attributes.merge(element_attributes).except(*FORBIDDEN_DEFINITION_ATTRIBUTES))
|
135
135
|
end
|
136
136
|
|
137
|
-
# The class responsible for the +dom_id+ of elements.
|
138
|
-
# Defaults to +Alchemy::Element::DomId+.
|
139
|
-
# @deprecated
|
140
|
-
def dom_id_class
|
141
|
-
if caller.none? { |l| l =~ Regexp.new("alchemy/element/presenters.rb:87:in `dom_id'") }
|
142
|
-
Alchemy::Deprecation.warn("dom_id_class is deprecated and will be removed from Alchemy 8.0. Please pass an id to the element_view_for helper instead.")
|
143
|
-
end
|
144
|
-
@_dom_id_class || DomId
|
145
|
-
end
|
146
|
-
|
147
|
-
# Register a custom +DomId+ class responsible for the +dom_id+ of elements.
|
148
|
-
# Defaults to +Alchemy::Element::DomId+.
|
149
|
-
# @deprecated
|
150
|
-
def dom_id_class=(klass)
|
151
|
-
@_dom_id_class = klass
|
152
|
-
end
|
153
|
-
deprecate :dom_id_class=, deprecator: Alchemy::Deprecation
|
154
|
-
|
155
137
|
# This methods does a copy of source and all its ingredients.
|
156
138
|
#
|
157
139
|
# == Options
|
@@ -185,7 +167,7 @@ module Alchemy
|
|
185
167
|
def all_from_clipboard_for_parent_element(clipboard, parent_element)
|
186
168
|
return none if clipboard.nil? || parent_element.nil?
|
187
169
|
|
188
|
-
all_from_clipboard(clipboard).where(name: parent_element.definition
|
170
|
+
all_from_clipboard(clipboard).where(name: parent_element.definition.nestable_elements)
|
189
171
|
end
|
190
172
|
end
|
191
173
|
|
@@ -229,7 +211,7 @@ module Alchemy
|
|
229
211
|
|
230
212
|
# Returns true if the definition of this element has a taggable true value.
|
231
213
|
def taggable?
|
232
|
-
definition
|
214
|
+
definition.taggable == true
|
233
215
|
end
|
234
216
|
|
235
217
|
# The opposite of folded?
|
@@ -239,7 +221,7 @@ module Alchemy
|
|
239
221
|
|
240
222
|
# Defined as compact element?
|
241
223
|
def compact?
|
242
|
-
definition
|
224
|
+
definition.compact
|
243
225
|
end
|
244
226
|
|
245
227
|
# Defined as deprecated element?
|
@@ -271,7 +253,7 @@ module Alchemy
|
|
271
253
|
#
|
272
254
|
# @return Boolean
|
273
255
|
def deprecated?
|
274
|
-
!!definition
|
256
|
+
!!definition.deprecated
|
275
257
|
end
|
276
258
|
|
277
259
|
# The element's view partial is dependent from its name
|
@@ -294,13 +276,13 @@ module Alchemy
|
|
294
276
|
|
295
277
|
# A collection of element names that can be nested inside this element.
|
296
278
|
def nestable_elements
|
297
|
-
definition.
|
279
|
+
definition.nestable_elements
|
298
280
|
end
|
299
281
|
|
300
282
|
private
|
301
283
|
|
302
284
|
def generate_nested_elements
|
303
|
-
definition.
|
285
|
+
definition.autogenerate.each do |nestable_element|
|
304
286
|
if nestable_elements.include?(nestable_element)
|
305
287
|
Element.create(page_version: page_version, parent_element_id: id, name: nestable_element)
|
306
288
|
else
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
class ElementDefinition
|
5
|
+
include ActiveModel::Model
|
6
|
+
include ActiveModel::Attributes
|
7
|
+
include Alchemy::Hints
|
8
|
+
|
9
|
+
extend ActiveModel::Translation
|
10
|
+
|
11
|
+
attribute :name, :string
|
12
|
+
attribute :unique, :boolean, default: false
|
13
|
+
attribute :amount, :integer, default: Float::INFINITY
|
14
|
+
attribute :taggable, :boolean, default: false
|
15
|
+
attribute :compact, :boolean, default: false
|
16
|
+
attribute :fixed, :boolean, default: false
|
17
|
+
attribute :ingredients, default: []
|
18
|
+
attribute :nestable_elements, default: []
|
19
|
+
attribute :autogenerate, default: []
|
20
|
+
attribute :deprecated
|
21
|
+
attribute :message
|
22
|
+
attribute :warning
|
23
|
+
attribute :hint
|
24
|
+
|
25
|
+
validates :name,
|
26
|
+
presence: true,
|
27
|
+
format: {
|
28
|
+
with: /\A[a-z_-]+\z/
|
29
|
+
}
|
30
|
+
|
31
|
+
delegate :blank?, to: :name
|
32
|
+
|
33
|
+
class << self
|
34
|
+
# Returns the definitions from elements.yml file.
|
35
|
+
#
|
36
|
+
# Place a +elements.yml+ file inside your apps +config/alchemy+ folder to define
|
37
|
+
# your own set of elements
|
38
|
+
#
|
39
|
+
def all
|
40
|
+
@definitions ||= read_definitions_file.map { new(**_1) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Add additional page definitions to collection.
|
44
|
+
#
|
45
|
+
# Useful for extending the elements from an Alchemy module.
|
46
|
+
#
|
47
|
+
# === Usage Example
|
48
|
+
#
|
49
|
+
# Call +Alchemy::ElementDefinition.add(your_definition)+ in your engine.rb file.
|
50
|
+
#
|
51
|
+
# @param [Array || Hash]
|
52
|
+
# You can pass a single element definition as Hash, or a collection of elements as Array.
|
53
|
+
#
|
54
|
+
def add(definition)
|
55
|
+
all
|
56
|
+
@definitions += Array.wrap(definition).map { new(**_1) }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns one element definition by given name.
|
60
|
+
#
|
61
|
+
def get(name)
|
62
|
+
return new if name.blank?
|
63
|
+
|
64
|
+
all.detect { _1.name.casecmp(name).zero? }
|
65
|
+
end
|
66
|
+
|
67
|
+
def reset!
|
68
|
+
@definitions = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# The absolute +elements.yml+ file path
|
72
|
+
# @return [Pathname]
|
73
|
+
def definitions_file_path
|
74
|
+
Rails.root.join("config", "alchemy", "elements.yml")
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def definitions_file
|
80
|
+
File.read(definitions_file_path)
|
81
|
+
end
|
82
|
+
|
83
|
+
def definitions_file_exist?
|
84
|
+
File.exist?(definitions_file_path)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Reads the element definitions from +config/alchemy/elements.yml+.
|
88
|
+
#
|
89
|
+
def read_definitions_file
|
90
|
+
if definitions_file_exist?
|
91
|
+
YAML.safe_load(
|
92
|
+
ERB.new(definitions_file).result,
|
93
|
+
permitted_classes: YAML_PERMITTED_CLASSES,
|
94
|
+
aliases: true
|
95
|
+
) || []
|
96
|
+
else
|
97
|
+
raise LoadError,
|
98
|
+
"Could not find elements.yml file! Please run `rails generate alchemy:install`"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def attributes
|
104
|
+
super.with_indifferent_access
|
105
|
+
end
|
106
|
+
|
107
|
+
def ingredients
|
108
|
+
super.map { IngredientDefinition.new(**_1) }
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns a deprecation notice for elements marked deprecated
|
112
|
+
#
|
113
|
+
# You can either use localizations or pass a String as notice
|
114
|
+
# in the element definition.
|
115
|
+
#
|
116
|
+
# == Custom deprecation notices
|
117
|
+
#
|
118
|
+
# Use general element deprecation notice
|
119
|
+
#
|
120
|
+
# - name: old_element
|
121
|
+
# deprecated: true
|
122
|
+
#
|
123
|
+
# Add a translation to your locale file for a per element notice.
|
124
|
+
#
|
125
|
+
# en:
|
126
|
+
# alchemy:
|
127
|
+
# element_deprecation_notices:
|
128
|
+
# old_element: Foo baz widget is deprecated
|
129
|
+
#
|
130
|
+
# or use the global translation that apply to all deprecated elements.
|
131
|
+
#
|
132
|
+
# en:
|
133
|
+
# alchemy:
|
134
|
+
# element_deprecation_notice: Foo baz widget is deprecated
|
135
|
+
#
|
136
|
+
# or pass string as deprecation notice.
|
137
|
+
#
|
138
|
+
# - name: old_element
|
139
|
+
# deprecated: This element will be removed soon.
|
140
|
+
#
|
141
|
+
def deprecation_notice
|
142
|
+
case deprecated
|
143
|
+
when String
|
144
|
+
deprecated
|
145
|
+
when TrueClass
|
146
|
+
Alchemy.t(
|
147
|
+
name,
|
148
|
+
scope: :element_deprecation_notices,
|
149
|
+
default: Alchemy.t(:element_deprecated)
|
150
|
+
)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def hint_translation_scope
|
157
|
+
:element_hints
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|