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
@@ -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",
|
@@ -38,6 +37,7 @@ module Alchemy
|
|
38
37
|
"compact",
|
39
38
|
"deprecated",
|
40
39
|
"hint",
|
40
|
+
"icon",
|
41
41
|
"ingredients",
|
42
42
|
"message",
|
43
43
|
"nestable_elements",
|
@@ -55,7 +55,7 @@ module Alchemy
|
|
55
55
|
#
|
56
56
|
acts_as_list scope: [:page_version_id, :fixed, :parent_element_id]
|
57
57
|
|
58
|
-
stampable stamper_class_name: Alchemy.
|
58
|
+
stampable stamper_class_name: Alchemy.user_class_name
|
59
59
|
|
60
60
|
before_destroy :delete_all_nested_elements
|
61
61
|
|
@@ -107,6 +107,7 @@ module Alchemy
|
|
107
107
|
scope :not_nested, -> { where(parent_element_id: nil) }
|
108
108
|
|
109
109
|
delegate :restricted?, to: :page, allow_nil: true
|
110
|
+
delegate :deprecation_notice, :has_hint?, :hint, to: :definition
|
110
111
|
|
111
112
|
# Concerns
|
112
113
|
include Definitions
|
@@ -131,27 +132,9 @@ module Alchemy
|
|
131
132
|
raise(ElementDefinitionError, attributes)
|
132
133
|
end
|
133
134
|
|
134
|
-
super(element_definition.merge(element_attributes).except(*FORBIDDEN_DEFINITION_ATTRIBUTES))
|
135
|
+
super(element_definition.attributes.merge(element_attributes).except(*FORBIDDEN_DEFINITION_ATTRIBUTES))
|
135
136
|
end
|
136
137
|
|
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
138
|
# This methods does a copy of source and all its ingredients.
|
156
139
|
#
|
157
140
|
# == Options
|
@@ -185,7 +168,7 @@ module Alchemy
|
|
185
168
|
def all_from_clipboard_for_parent_element(clipboard, parent_element)
|
186
169
|
return none if clipboard.nil? || parent_element.nil?
|
187
170
|
|
188
|
-
all_from_clipboard(clipboard).where(name: parent_element.definition
|
171
|
+
all_from_clipboard(clipboard).where(name: parent_element.definition.nestable_elements)
|
189
172
|
end
|
190
173
|
end
|
191
174
|
|
@@ -229,7 +212,7 @@ module Alchemy
|
|
229
212
|
|
230
213
|
# Returns true if the definition of this element has a taggable true value.
|
231
214
|
def taggable?
|
232
|
-
definition
|
215
|
+
definition.taggable == true
|
233
216
|
end
|
234
217
|
|
235
218
|
# The opposite of folded?
|
@@ -239,7 +222,7 @@ module Alchemy
|
|
239
222
|
|
240
223
|
# Defined as compact element?
|
241
224
|
def compact?
|
242
|
-
definition
|
225
|
+
definition.compact
|
243
226
|
end
|
244
227
|
|
245
228
|
# Defined as deprecated element?
|
@@ -271,7 +254,7 @@ module Alchemy
|
|
271
254
|
#
|
272
255
|
# @return Boolean
|
273
256
|
def deprecated?
|
274
|
-
!!definition
|
257
|
+
!!definition.deprecated
|
275
258
|
end
|
276
259
|
|
277
260
|
# The element's view partial is dependent from its name
|
@@ -294,13 +277,13 @@ module Alchemy
|
|
294
277
|
|
295
278
|
# A collection of element names that can be nested inside this element.
|
296
279
|
def nestable_elements
|
297
|
-
definition.
|
280
|
+
definition.nestable_elements
|
298
281
|
end
|
299
282
|
|
300
283
|
private
|
301
284
|
|
302
285
|
def generate_nested_elements
|
303
|
-
definition.
|
286
|
+
definition.autogenerate.each do |nestable_element|
|
304
287
|
if nestable_elements.include?(nestable_element)
|
305
288
|
Element.create(page_version: page_version, parent_element_id: id, name: nestable_element)
|
306
289
|
else
|
@@ -0,0 +1,190 @@
|
|
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
|
+
attribute :icon
|
25
|
+
|
26
|
+
validates :name,
|
27
|
+
presence: true,
|
28
|
+
format: {
|
29
|
+
with: /\A[a-z_-]+\z/
|
30
|
+
}
|
31
|
+
|
32
|
+
validates :icon,
|
33
|
+
format: {with: /\A[\w-]+\z/i},
|
34
|
+
if: -> { icon.is_a?(String) }
|
35
|
+
|
36
|
+
delegate :blank?, to: :name
|
37
|
+
|
38
|
+
class << self
|
39
|
+
# Returns the definitions from elements.yml file.
|
40
|
+
#
|
41
|
+
# Place a +elements.yml+ file inside your apps +config/alchemy+ folder to define
|
42
|
+
# your own set of elements
|
43
|
+
#
|
44
|
+
def all
|
45
|
+
@definitions ||= read_definitions_file.map { new(**_1) }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add additional page definitions to collection.
|
49
|
+
#
|
50
|
+
# Useful for extending the elements from an Alchemy module.
|
51
|
+
#
|
52
|
+
# === Usage Example
|
53
|
+
#
|
54
|
+
# Call +Alchemy::ElementDefinition.add(your_definition)+ in your engine.rb file.
|
55
|
+
#
|
56
|
+
# @param [Array || Hash]
|
57
|
+
# You can pass a single element definition as Hash, or a collection of elements as Array.
|
58
|
+
#
|
59
|
+
def add(definition)
|
60
|
+
all
|
61
|
+
@definitions += Array.wrap(definition).map { new(**_1) }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns one element definition by given name.
|
65
|
+
#
|
66
|
+
def get(name)
|
67
|
+
return new if name.blank?
|
68
|
+
|
69
|
+
all.detect { _1.name.casecmp(name).zero? }
|
70
|
+
end
|
71
|
+
|
72
|
+
def reset!
|
73
|
+
@definitions = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
# The absolute +elements.yml+ file path
|
77
|
+
# @return [Pathname]
|
78
|
+
def definitions_file_path
|
79
|
+
Rails.root.join("config", "alchemy", "elements.yml")
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def definitions_file
|
85
|
+
File.read(definitions_file_path)
|
86
|
+
end
|
87
|
+
|
88
|
+
def definitions_file_exist?
|
89
|
+
File.exist?(definitions_file_path)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Reads the element definitions from +config/alchemy/elements.yml+.
|
93
|
+
#
|
94
|
+
def read_definitions_file
|
95
|
+
if definitions_file_exist?
|
96
|
+
YAML.safe_load(
|
97
|
+
ERB.new(definitions_file).result,
|
98
|
+
permitted_classes: YAML_PERMITTED_CLASSES,
|
99
|
+
aliases: true
|
100
|
+
) || []
|
101
|
+
else
|
102
|
+
raise LoadError,
|
103
|
+
"Could not find elements.yml file! Please run `rails generate alchemy:install`"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def attributes
|
109
|
+
super.with_indifferent_access
|
110
|
+
end
|
111
|
+
|
112
|
+
def ingredients
|
113
|
+
super.map { IngredientDefinition.new(**_1) }
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns a deprecation notice for elements marked deprecated
|
117
|
+
#
|
118
|
+
# You can either use localizations or pass a String as notice
|
119
|
+
# in the element definition.
|
120
|
+
#
|
121
|
+
# == Custom deprecation notices
|
122
|
+
#
|
123
|
+
# Use general element deprecation notice
|
124
|
+
#
|
125
|
+
# - name: old_element
|
126
|
+
# deprecated: true
|
127
|
+
#
|
128
|
+
# Add a translation to your locale file for a per element notice.
|
129
|
+
#
|
130
|
+
# en:
|
131
|
+
# alchemy:
|
132
|
+
# element_deprecation_notices:
|
133
|
+
# old_element: Foo baz widget is deprecated
|
134
|
+
#
|
135
|
+
# or use the global translation that apply to all deprecated elements.
|
136
|
+
#
|
137
|
+
# en:
|
138
|
+
# alchemy:
|
139
|
+
# element_deprecation_notice: Foo baz widget is deprecated
|
140
|
+
#
|
141
|
+
# or pass string as deprecation notice.
|
142
|
+
#
|
143
|
+
# - name: old_element
|
144
|
+
# deprecated: This element will be removed soon.
|
145
|
+
#
|
146
|
+
def deprecation_notice
|
147
|
+
case deprecated
|
148
|
+
when String
|
149
|
+
deprecated
|
150
|
+
when TrueClass
|
151
|
+
Alchemy.t(
|
152
|
+
name,
|
153
|
+
scope: :element_deprecation_notices,
|
154
|
+
default: Alchemy.t(:element_deprecated)
|
155
|
+
)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def icon_file
|
160
|
+
@_icon_file ||= File.read(icon_file_path).html_safe
|
161
|
+
end
|
162
|
+
|
163
|
+
def icon_file_name
|
164
|
+
"#{icon_name}.svg"
|
165
|
+
end
|
166
|
+
|
167
|
+
def icon_name
|
168
|
+
case icon
|
169
|
+
when TrueClass then name
|
170
|
+
when String then icon
|
171
|
+
else
|
172
|
+
"default"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def icon_file_path
|
179
|
+
icons_root_path.join("app/assets/images/alchemy/element_icons", icon_file_name)
|
180
|
+
end
|
181
|
+
|
182
|
+
def icons_root_path
|
183
|
+
icon.nil? ? Alchemy::Engine.root : Rails.root
|
184
|
+
end
|
185
|
+
|
186
|
+
def hint_translation_scope
|
187
|
+
:element_hints
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -4,8 +4,6 @@ module Alchemy
|
|
4
4
|
class Ingredient < BaseRecord
|
5
5
|
class DefinitionError < StandardError; end
|
6
6
|
|
7
|
-
include Hints
|
8
|
-
|
9
7
|
self.table_name = "alchemy_ingredients"
|
10
8
|
|
11
9
|
attribute :data, :json
|
@@ -16,7 +14,7 @@ module Alchemy
|
|
16
14
|
has_one :page, through: :element, class_name: "Alchemy::Page"
|
17
15
|
|
18
16
|
after_initialize :set_default_value,
|
19
|
-
if: -> { definition.
|
17
|
+
if: -> { definition.default && value.nil? }
|
20
18
|
|
21
19
|
validates :type, presence: true
|
22
20
|
validates :role, presence: true, uniqueness: {scope: :element_id, case_sensitive: false}
|
@@ -38,6 +36,8 @@ module Alchemy
|
|
38
36
|
scope :texts, -> { where(type: "Alchemy::Ingredients::Text") }
|
39
37
|
scope :videos, -> { where(type: "Alchemy::Ingredients::Video") }
|
40
38
|
|
39
|
+
delegate :has_hint?, :hint, to: :definition
|
40
|
+
|
41
41
|
class << self
|
42
42
|
# Defines getter and setter method aliases for related object
|
43
43
|
#
|
@@ -97,15 +97,15 @@ module Alchemy
|
|
97
97
|
|
98
98
|
# Settings for this ingredient from the +elements.yml+ definition.
|
99
99
|
def settings
|
100
|
-
definition
|
100
|
+
definition.settings
|
101
101
|
end
|
102
102
|
|
103
103
|
# Definition hash for this ingredient from +elements.yml+ file.
|
104
104
|
#
|
105
105
|
def definition
|
106
|
-
return
|
106
|
+
return IngredientDefinition.new unless element
|
107
107
|
|
108
|
-
element.ingredient_definition_for(role) ||
|
108
|
+
element.ingredient_definition_for(role) || IngredientDefinition.new
|
109
109
|
end
|
110
110
|
|
111
111
|
# The first 30 characters of the value
|
@@ -118,12 +118,6 @@ module Alchemy
|
|
118
118
|
value.to_s[0..maxlength - 1]
|
119
119
|
end
|
120
120
|
|
121
|
-
# The path to the view partial of the ingredient
|
122
|
-
# @return [String]
|
123
|
-
def to_partial_path
|
124
|
-
"alchemy/ingredients/#{partial_name}_view"
|
125
|
-
end
|
126
|
-
|
127
121
|
# The demodulized underscored class name of the ingredient
|
128
122
|
# @return [String]
|
129
123
|
def partial_name
|
@@ -132,17 +126,12 @@ module Alchemy
|
|
132
126
|
|
133
127
|
# @return [Boolean]
|
134
128
|
def has_validations?
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
|
-
# @return [Boolean]
|
139
|
-
def has_hint?
|
140
|
-
!!definition[:hint]
|
129
|
+
definition.validate.any?
|
141
130
|
end
|
142
131
|
|
143
132
|
# @return [Boolean]
|
144
133
|
def deprecated?
|
145
|
-
!!definition
|
134
|
+
!!definition.deprecated
|
146
135
|
end
|
147
136
|
|
148
137
|
# @return [Boolean]
|
@@ -152,7 +141,7 @@ module Alchemy
|
|
152
141
|
|
153
142
|
# @return [Boolean]
|
154
143
|
def preview_ingredient?
|
155
|
-
!!definition
|
144
|
+
!!definition.as_element_title
|
156
145
|
end
|
157
146
|
|
158
147
|
# The view component of the ingredient with mapped options.
|
@@ -169,30 +158,8 @@ module Alchemy
|
|
169
158
|
@_view_component_class ||= "#{self.class.name}View".constantize
|
170
159
|
end
|
171
160
|
|
172
|
-
def hint_translation_attribute
|
173
|
-
role
|
174
|
-
end
|
175
|
-
|
176
|
-
def hint_translation_scope
|
177
|
-
"ingredient_hints"
|
178
|
-
end
|
179
|
-
|
180
161
|
def set_default_value
|
181
|
-
self.value = default_value
|
182
|
-
end
|
183
|
-
|
184
|
-
# Returns the default value from ingredient definition
|
185
|
-
#
|
186
|
-
# If the value is a symbol it gets passed through i18n
|
187
|
-
# inside the +alchemy.default_ingredient_texts+ scope
|
188
|
-
def default_value
|
189
|
-
default = definition[:default]
|
190
|
-
case default
|
191
|
-
when Symbol
|
192
|
-
Alchemy.t(default, scope: :default_ingredient_texts)
|
193
|
-
else
|
194
|
-
default
|
195
|
-
end
|
162
|
+
self.value = definition.default_value
|
196
163
|
end
|
197
164
|
end
|
198
165
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
class IngredientDefinition
|
5
|
+
include ActiveModel::Model
|
6
|
+
include ActiveModel::Attributes
|
7
|
+
include Alchemy::Hints
|
8
|
+
|
9
|
+
extend ActiveModel::Translation
|
10
|
+
|
11
|
+
attribute :role, :string
|
12
|
+
attribute :type, :string
|
13
|
+
attribute :as_element_title, :boolean, default: false
|
14
|
+
attribute :settings, default: {}
|
15
|
+
attribute :validate, default: []
|
16
|
+
attribute :group, :string
|
17
|
+
attribute :default
|
18
|
+
attribute :deprecated
|
19
|
+
attribute :hint
|
20
|
+
|
21
|
+
validates :role,
|
22
|
+
presence: true,
|
23
|
+
format: {
|
24
|
+
with: /\A[a-z_-]+\z/
|
25
|
+
}
|
26
|
+
|
27
|
+
validates :type,
|
28
|
+
presence: true,
|
29
|
+
format: {
|
30
|
+
with: /\A[A-Z][a-zA-Z]+\z/
|
31
|
+
}
|
32
|
+
|
33
|
+
delegate :blank?, to: :role
|
34
|
+
|
35
|
+
def attributes
|
36
|
+
super.with_indifferent_access
|
37
|
+
end
|
38
|
+
|
39
|
+
def settings
|
40
|
+
super.with_indifferent_access
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate
|
44
|
+
super.map do |validation|
|
45
|
+
case validation
|
46
|
+
when Hash
|
47
|
+
validation.with_indifferent_access
|
48
|
+
else
|
49
|
+
validation
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the default value from ingredient definition
|
55
|
+
#
|
56
|
+
# If the value is a symbol it gets passed through i18n
|
57
|
+
# inside the +alchemy.default_ingredient_texts+ scope
|
58
|
+
def default_value
|
59
|
+
case default
|
60
|
+
when Symbol
|
61
|
+
Alchemy.t(default, scope: :default_ingredient_texts)
|
62
|
+
when String
|
63
|
+
default
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns a deprecation notice for ingredients marked deprecated
|
68
|
+
#
|
69
|
+
# You can either use localizations or pass a String as notice
|
70
|
+
# in the ingredient definition.
|
71
|
+
#
|
72
|
+
# == Custom deprecation notices
|
73
|
+
#
|
74
|
+
# Use general ingredient deprecation notice
|
75
|
+
#
|
76
|
+
# - name: element_name
|
77
|
+
# ingredients:
|
78
|
+
# - role: old_ingredient
|
79
|
+
# type: Text
|
80
|
+
# deprecated: true
|
81
|
+
#
|
82
|
+
# Add a translation to your locale file for a per ingredient notice.
|
83
|
+
#
|
84
|
+
# en:
|
85
|
+
# alchemy:
|
86
|
+
# ingredient_deprecation_notices:
|
87
|
+
# old_ingredient: Foo baz widget is deprecated
|
88
|
+
#
|
89
|
+
# You can scope the translation per element as well.
|
90
|
+
#
|
91
|
+
# en:
|
92
|
+
# alchemy:
|
93
|
+
# ingredient_deprecation_notices:
|
94
|
+
# element_name:
|
95
|
+
# old_ingredient: Elements foo baz widget is deprecated
|
96
|
+
#
|
97
|
+
# or use the global translation that apply to all deprecated ingredients.
|
98
|
+
#
|
99
|
+
# en:
|
100
|
+
# alchemy:
|
101
|
+
# ingredient_deprecation_notice: Foo baz widget is deprecated
|
102
|
+
#
|
103
|
+
# or pass string as deprecation notice.
|
104
|
+
#
|
105
|
+
# - name: element_name
|
106
|
+
# ingredients:
|
107
|
+
# - role: old_ingredient
|
108
|
+
# type: Text
|
109
|
+
# deprecated: This ingredient will be removed soon.
|
110
|
+
#
|
111
|
+
def deprecation_notice(element_name: nil)
|
112
|
+
case deprecated
|
113
|
+
when String
|
114
|
+
deprecated
|
115
|
+
when TrueClass
|
116
|
+
Alchemy.t(
|
117
|
+
role,
|
118
|
+
scope: [:ingredient_deprecation_notices, element_name].compact,
|
119
|
+
default: Alchemy.t(:ingredient_deprecated)
|
120
|
+
)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def hint_translation_scope
|
127
|
+
:ingredient_hints
|
128
|
+
end
|
129
|
+
|
130
|
+
def hint_translation_attribute
|
131
|
+
role
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -64,7 +64,7 @@ module Alchemy
|
|
64
64
|
attr_reader :ingredient
|
65
65
|
|
66
66
|
def validations
|
67
|
-
ingredient.definition.
|
67
|
+
ingredient.definition.validate
|
68
68
|
end
|
69
69
|
|
70
70
|
def validate_presence(*)
|
@@ -80,8 +80,12 @@ module Alchemy
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def validate_format(format)
|
83
|
-
matcher =
|
84
|
-
|
83
|
+
matcher = if format.is_a?(String) || format.is_a?(Symbol)
|
84
|
+
Alchemy.config.format_matchers.get(format)
|
85
|
+
else
|
86
|
+
format
|
87
|
+
end
|
88
|
+
if !ingredient.value.to_s.match?(matcher)
|
85
89
|
ingredient.errors.add(:value, :invalid)
|
86
90
|
end
|
87
91
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module Ingredients
|
5
|
+
# A number
|
6
|
+
#
|
7
|
+
# Either a decimal or integer number
|
8
|
+
#
|
9
|
+
class Number < Alchemy::Ingredient
|
10
|
+
allow_settings %i[
|
11
|
+
input_type
|
12
|
+
step
|
13
|
+
min
|
14
|
+
max
|
15
|
+
unit
|
16
|
+
]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -25,8 +25,8 @@ require_dependency "alchemy/site"
|
|
25
25
|
module Alchemy
|
26
26
|
class Language < BaseRecord
|
27
27
|
belongs_to :site
|
28
|
-
has_many :pages, inverse_of: :language
|
29
|
-
has_many :nodes, inverse_of: :language
|
28
|
+
has_many :pages, inverse_of: :language, dependent: :restrict_with_error
|
29
|
+
has_many :nodes, inverse_of: :language, dependent: :restrict_with_error
|
30
30
|
|
31
31
|
before_validation :set_locale, if: -> { locale.blank? }
|
32
32
|
|
@@ -54,11 +54,6 @@ module Alchemy
|
|
54
54
|
after_update :set_pages_language,
|
55
55
|
if: :should_set_pages_language?
|
56
56
|
|
57
|
-
before_destroy if: -> { pages.any? } do
|
58
|
-
errors.add(:pages, :still_present)
|
59
|
-
throw(:abort)
|
60
|
-
end
|
61
|
-
|
62
57
|
scope :published, -> { where(public: true) }
|
63
58
|
scope :with_root_page, -> { joins(:pages).where(Page.table_name => {language_root: true}) }
|
64
59
|
|
@@ -71,20 +66,6 @@ module Alchemy
|
|
71
66
|
on_site(Current.site)
|
72
67
|
end
|
73
68
|
|
74
|
-
# Store the current language in the current thread.
|
75
|
-
# @deprecated Use {Alchemy::Current#language=} instead.
|
76
|
-
def current=(language)
|
77
|
-
Current.language = language
|
78
|
-
end
|
79
|
-
deprecate "current=": :"Alchemy::Current.language=", deprecator: Alchemy::Deprecation
|
80
|
-
|
81
|
-
# Current language from current thread or default.
|
82
|
-
# @deprecated Use {Alchemy::Current#language} instead.
|
83
|
-
def current
|
84
|
-
Current.language
|
85
|
-
end
|
86
|
-
deprecate current: :"Alchemy::Current.language", deprecator: Alchemy::Deprecation
|
87
|
-
|
88
69
|
# The root page of the current language.
|
89
70
|
def current_root_page
|
90
71
|
Current.language&.pages&.language_roots&.first
|
@@ -16,23 +16,19 @@ module Alchemy
|
|
16
16
|
class Message
|
17
17
|
include ActiveModel::Model
|
18
18
|
|
19
|
-
def self.config
|
20
|
-
Alchemy::Config.get(:mailer)
|
21
|
-
end
|
22
|
-
|
23
19
|
attr_accessor :contact_form_id, :ip
|
24
20
|
|
25
|
-
config
|
21
|
+
Alchemy.config.mailer.fields.each do |field|
|
26
22
|
attr_accessor field.to_sym
|
27
23
|
end
|
28
24
|
|
29
|
-
config
|
25
|
+
Alchemy.config.mailer.validate_fields.each do |field|
|
30
26
|
validates_presence_of field
|
31
27
|
|
32
28
|
case field.to_sym
|
33
29
|
when /email/
|
34
30
|
validates_format_of field,
|
35
|
-
with: Alchemy
|
31
|
+
with: Alchemy.config.format_matchers.email,
|
36
32
|
if: -> { send(field).present? }
|
37
33
|
when :email_confirmation
|
38
34
|
validates_confirmation_of :email
|
data/app/models/alchemy/node.rb
CHANGED
@@ -7,7 +7,7 @@ module Alchemy
|
|
7
7
|
before_destroy :check_if_related_node_ingredients_present
|
8
8
|
|
9
9
|
acts_as_nested_set scope: "language_id", touch: true
|
10
|
-
stampable stamper_class_name: Alchemy.
|
10
|
+
stampable stamper_class_name: Alchemy.user_class_name
|
11
11
|
|
12
12
|
belongs_to :language, class_name: "Alchemy::Language"
|
13
13
|
belongs_to :page, class_name: "Alchemy::Page", optional: true, inverse_of: :nodes
|