alchemy_cms 4.6.1 → 5.0.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +33 -1
- data/.github/workflows/stale.yml +1 -1
- data/.gitignore +20 -2
- data/.hound.yml +2 -1
- data/.prettierrc +6 -0
- data/.rubocop.yml +30 -9
- data/CHANGELOG.md +102 -1
- data/Gemfile +24 -22
- data/README.md +32 -20
- data/Rakefile +11 -8
- data/alchemy_cms.gemspec +6 -5
- data/app/assets/javascripts/alchemy/admin.js +1 -5
- data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +2 -1
- data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +0 -2
- data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +17 -17
- data/app/assets/javascripts/alchemy/node_select.js +39 -0
- data/app/assets/javascripts/alchemy/templates/index.js +1 -0
- data/app/assets/javascripts/alchemy/templates/node.hbs +16 -0
- data/app/assets/stylesheets/alchemy/admin.scss +3 -2
- data/app/assets/stylesheets/alchemy/base.scss +0 -1
- data/app/assets/stylesheets/alchemy/elements.scss +1 -1
- data/app/assets/stylesheets/alchemy/forms.scss +5 -0
- data/app/assets/stylesheets/alchemy/navigation.scss +1 -0
- data/app/assets/stylesheets/alchemy/node-select.scss +43 -0
- data/app/assets/stylesheets/alchemy/nodes.scss +1 -1
- data/app/assets/stylesheets/alchemy/sitemap.scss +5 -1
- data/app/assets/stylesheets/alchemy/tables.scss +1 -24
- data/app/assets/stylesheets/alchemy/tags.scss +2 -2
- data/app/controllers/alchemy/admin/attachments_controller.rb +8 -7
- data/app/controllers/alchemy/admin/base_controller.rb +13 -33
- data/app/controllers/alchemy/admin/clipboard_controller.rb +5 -4
- data/app/controllers/alchemy/admin/contents_controller.rb +1 -2
- data/app/controllers/alchemy/admin/dashboard_controller.rb +10 -9
- data/app/controllers/alchemy/admin/elements_controller.rb +20 -20
- data/app/controllers/alchemy/admin/essence_pictures_controller.rb +12 -14
- data/app/controllers/alchemy/admin/languages_controller.rb +35 -2
- data/app/controllers/alchemy/admin/layoutpages_controller.rb +5 -2
- data/app/controllers/alchemy/admin/nodes_controller.rb +5 -4
- data/app/controllers/alchemy/admin/pages_controller.rb +51 -63
- data/app/controllers/alchemy/admin/pictures_controller.rb +16 -16
- data/app/controllers/alchemy/admin/resources_controller.rb +21 -13
- data/app/controllers/alchemy/admin/sites_controller.rb +18 -0
- data/app/controllers/alchemy/admin/styleguide_controller.rb +1 -0
- data/app/controllers/alchemy/admin/tags_controller.rb +5 -3
- data/app/controllers/alchemy/admin/trash_controller.rb +6 -6
- data/app/controllers/alchemy/api/base_controller.rb +2 -2
- data/app/controllers/alchemy/api/contents_controller.rb +4 -4
- data/app/controllers/alchemy/api/elements_controller.rb +8 -8
- data/app/controllers/alchemy/api/nodes_controller.rb +37 -1
- data/app/controllers/alchemy/api/pages_controller.rb +14 -23
- data/app/controllers/alchemy/attachments_controller.rb +5 -5
- data/app/controllers/alchemy/base_controller.rb +10 -9
- data/app/controllers/alchemy/messages_controller.rb +16 -23
- data/app/controllers/alchemy/pages_controller.rb +13 -11
- data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +3 -2
- data/app/controllers/concerns/alchemy/admin/current_language.rb +23 -0
- data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +5 -5
- data/app/controllers/concerns/alchemy/legacy_page_redirects.rb +4 -4
- data/app/controllers/concerns/alchemy/page_redirects.rb +2 -9
- data/app/controllers/concerns/alchemy/site_redirects.rb +2 -2
- data/app/decorators/alchemy/element_editor.rb +39 -0
- data/app/helpers/alchemy/admin/attachments_helper.rb +6 -6
- data/app/helpers/alchemy/admin/base_helper.rb +38 -35
- data/app/helpers/alchemy/admin/contents_helper.rb +3 -3
- data/app/helpers/alchemy/admin/elements_helper.rb +3 -88
- data/app/helpers/alchemy/admin/essences_helper.rb +8 -117
- data/app/helpers/alchemy/admin/form_helper.rb +1 -1
- data/app/helpers/alchemy/admin/navigation_helper.rb +24 -23
- data/app/helpers/alchemy/admin/pages_helper.rb +4 -4
- data/app/helpers/alchemy/admin/pictures_helper.rb +4 -6
- data/app/helpers/alchemy/admin/tags_helper.rb +8 -7
- data/app/helpers/alchemy/base_helper.rb +13 -8
- data/app/helpers/alchemy/elements_block_helper.rb +2 -31
- data/app/helpers/alchemy/elements_helper.rb +12 -58
- data/app/helpers/alchemy/pages_helper.rb +24 -174
- data/app/helpers/alchemy/url_helper.rb +4 -3
- data/app/mailers/alchemy/base_mailer.rb +1 -1
- data/app/mailers/alchemy/messages_mailer.rb +1 -1
- data/app/models/alchemy/attachment.rb +24 -19
- data/app/models/alchemy/base_record.rb +2 -5
- data/app/models/alchemy/content.rb +33 -38
- data/app/models/alchemy/content/factory.rb +24 -31
- data/app/models/alchemy/element.rb +45 -53
- data/app/models/alchemy/element/definitions.rb +4 -4
- data/app/models/alchemy/element/element_contents.rb +9 -6
- data/app/models/alchemy/element/element_essences.rb +4 -3
- data/app/models/alchemy/element/presenters.rb +3 -2
- data/app/models/alchemy/element_to_page.rb +1 -1
- data/app/models/alchemy/essence_boolean.rb +1 -3
- data/app/models/alchemy/essence_date.rb +2 -3
- data/app/models/alchemy/essence_file.rb +5 -5
- data/app/models/alchemy/essence_html.rb +1 -3
- data/app/models/alchemy/essence_link.rb +1 -3
- data/app/models/alchemy/essence_node.rb +18 -0
- data/app/models/alchemy/essence_page.rb +3 -16
- data/app/models/alchemy/essence_picture.rb +18 -17
- data/app/models/alchemy/essence_picture_view.rb +7 -6
- data/app/models/alchemy/essence_richtext.rb +1 -3
- data/app/models/alchemy/essence_select.rb +1 -3
- data/app/models/alchemy/essence_text.rb +0 -2
- data/app/models/alchemy/folded_page.rb +1 -0
- data/app/models/alchemy/language.rb +21 -35
- data/app/models/alchemy/language/code.rb +4 -4
- data/app/models/alchemy/legacy_page_url.rb +1 -1
- data/app/models/alchemy/message.rb +3 -3
- data/app/models/alchemy/node.rb +27 -4
- data/app/models/alchemy/page.rb +46 -127
- data/app/models/alchemy/page/fixed_attributes.rb +3 -2
- data/app/models/alchemy/page/page_elements.rb +35 -44
- data/app/models/alchemy/page/page_naming.rb +20 -70
- data/app/models/alchemy/page/page_natures.rb +7 -34
- data/app/models/alchemy/page/page_scopes.rb +23 -29
- data/app/models/alchemy/page/url_path.rb +0 -2
- data/app/models/alchemy/picture.rb +40 -30
- data/app/models/alchemy/picture/preprocessor.rb +26 -0
- data/app/models/alchemy/picture/transformations.rb +9 -7
- data/app/models/alchemy/picture/url.rb +9 -7
- data/app/models/alchemy/site.rb +6 -36
- data/app/models/alchemy/site/layout.rb +2 -2
- data/app/models/concerns/alchemy/touch_elements.rb +24 -0
- data/app/serializers/alchemy/content_serializer.rb +0 -3
- data/app/serializers/alchemy/essence_boolean_serializer.rb +3 -3
- data/app/serializers/alchemy/essence_date_serializer.rb +3 -3
- data/app/serializers/alchemy/essence_file_serializer.rb +4 -2
- data/app/serializers/alchemy/essence_html_serializer.rb +3 -3
- data/app/serializers/alchemy/essence_link_serializer.rb +3 -3
- data/app/serializers/alchemy/essence_picture_serializer.rb +5 -4
- data/app/serializers/alchemy/essence_richtext_serializer.rb +3 -3
- data/app/serializers/alchemy/essence_select_serializer.rb +3 -3
- data/app/serializers/alchemy/essence_text_serializer.rb +5 -4
- data/app/serializers/alchemy/node_serializer.rb +2 -0
- data/app/serializers/alchemy/page_tree_serializer.rb +9 -13
- data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +1 -2
- data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +1 -2
- data/app/views/alchemy/admin/attachments/_files_list.html.erb +4 -4
- data/app/views/alchemy/admin/contents/create.js.erb +1 -3
- data/app/views/alchemy/admin/elements/_element.html.erb +9 -18
- data/app/views/alchemy/admin/elements/create.js.erb +1 -1
- data/app/views/alchemy/admin/elements/fold.js.erb +1 -1
- data/app/views/alchemy/admin/elements/index.html.erb +3 -3
- data/app/views/alchemy/admin/essence_files/assign.js.erb +1 -6
- data/app/views/alchemy/admin/essence_files/edit.html.erb +1 -1
- data/app/views/alchemy/admin/essence_pictures/assign.js.erb +1 -7
- data/app/views/alchemy/admin/essence_pictures/crop.html.erb +1 -1
- data/app/views/alchemy/admin/essence_pictures/edit.html.erb +7 -7
- data/app/views/alchemy/admin/essence_pictures/update.js.erb +1 -1
- data/app/views/alchemy/admin/languages/_form.html.erb +5 -5
- data/app/views/alchemy/admin/languages/_table.html.erb +3 -3
- data/app/views/alchemy/admin/languages/edit.html.erb +1 -0
- data/app/views/alchemy/admin/languages/index.html.erb +23 -4
- data/app/views/alchemy/admin/languages/new.html.erb +1 -0
- data/app/views/alchemy/admin/layoutpages/index.html.erb +3 -3
- data/app/views/alchemy/admin/nodes/_form.html.erb +18 -15
- data/app/views/alchemy/admin/nodes/_node.html.erb +1 -5
- data/app/views/alchemy/admin/nodes/index.html.erb +3 -4
- data/app/views/alchemy/admin/pages/_create_language_form.html.erb +0 -8
- data/app/views/alchemy/admin/pages/_form.html.erb +0 -1
- data/app/views/alchemy/admin/pages/_new_page_form.html.erb +1 -0
- data/app/views/alchemy/admin/pages/_page.html.erb +11 -19
- data/app/views/alchemy/admin/pages/_page_infos.html.erb +0 -4
- data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
- data/app/views/alchemy/admin/pages/info.html.erb +0 -9
- data/app/views/alchemy/admin/pages/unlock.js.erb +13 -6
- data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +0 -2
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -5
- data/app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -2
- data/app/views/alchemy/admin/pictures/index.html.erb +18 -3
- data/app/views/alchemy/admin/pictures/show.html.erb +1 -1
- data/app/views/alchemy/admin/resources/_resource.html.erb +1 -1
- data/app/views/alchemy/admin/resources/_table.html.erb +2 -2
- data/app/views/alchemy/admin/resources/index.html.erb +21 -22
- data/app/views/alchemy/admin/sites/_form.html.erb +8 -0
- data/app/views/alchemy/admin/sites/edit.html.erb +1 -0
- data/app/views/alchemy/admin/sites/index.html.erb +21 -9
- data/app/views/alchemy/admin/sites/new.html.erb +1 -0
- data/app/views/alchemy/admin/tags/index.html.erb +2 -2
- data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +10 -12
- data/app/views/alchemy/essences/_essence_date_editor.html.erb +11 -8
- data/app/views/alchemy/essences/_essence_file_editor.html.erb +16 -17
- data/app/views/alchemy/essences/_essence_file_view.html.erb +1 -1
- data/app/views/alchemy/essences/_essence_html_editor.html.erb +8 -5
- data/app/views/alchemy/essences/_essence_link_editor.html.erb +18 -15
- data/app/views/alchemy/essences/_essence_node_editor.html.erb +27 -0
- data/app/views/alchemy/essences/_essence_node_view.html.erb +1 -0
- data/app/views/alchemy/essences/_essence_page_editor.html.erb +14 -11
- data/app/views/alchemy/essences/_essence_picture_editor.html.erb +22 -20
- data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +10 -7
- data/app/views/alchemy/essences/_essence_select_editor.html.erb +12 -16
- data/app/views/alchemy/essences/_essence_text_editor.html.erb +18 -17
- data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +6 -11
- data/app/views/alchemy/pages/show.rss.builder +3 -2
- data/app/views/layouts/alchemy/admin.html.erb +1 -0
- data/babel.config.js +12 -0
- data/bin/rails +5 -4
- data/config/alchemy/config.yml +23 -16
- data/config/brakeman.ignore +1 -1
- data/config/initializers/assets.rb +2 -1
- data/config/initializers/dragonfly.rb +2 -1
- data/config/initializers/mime_types.rb +1 -0
- data/config/initializers/mini_profiler.rb +3 -2
- data/config/initializers/simple_form.rb +6 -6
- data/config/locales/alchemy.en.yml +23 -8
- data/config/routes.rb +25 -24
- data/config/spring.rb +3 -2
- data/db/migrate/20200226213334_alchemy_four_point_four.rb +313 -0
- data/db/migrate/20200423073425_create_alchemy_essence_nodes.rb +11 -0
- data/db/migrate/20200504210159_remove_site_id_from_nodes.rb +28 -0
- data/db/migrate/20200505215518_add_language_id_foreign_key_to_alchemy_pages.rb +8 -0
- data/db/migrate/20200511113603_add_menu_type_to_alchemy_nodes.rb +27 -0
- data/db/migrate/20200514091507_make_page_layoutpage_null_false.rb +6 -0
- data/db/migrate/20200519073500_remove_visible_from_alchemy_pages.rb +24 -0
- data/lib/alchemy/admin/locale.rb +3 -1
- data/lib/alchemy/admin/preview_url.rb +85 -0
- data/lib/alchemy/auth_accessors.rb +8 -7
- data/lib/alchemy/cache_digests/template_tracker.rb +5 -4
- data/lib/alchemy/config.rb +3 -5
- data/lib/alchemy/configuration_methods.rb +3 -1
- data/lib/alchemy/controller_actions.rb +6 -5
- data/lib/alchemy/deprecation.rb +2 -1
- data/lib/alchemy/elements_finder.rb +5 -5
- data/lib/alchemy/engine.rb +23 -8
- data/lib/alchemy/errors.rb +0 -7
- data/lib/alchemy/essence.rb +17 -16
- data/lib/alchemy/filetypes.rb +5 -5
- data/lib/alchemy/forms/builder.rb +4 -4
- data/lib/alchemy/hints.rb +1 -1
- data/lib/alchemy/i18n.rb +2 -1
- data/lib/alchemy/install/tasks.rb +41 -0
- data/lib/alchemy/modules.rb +12 -12
- data/lib/alchemy/name_conversions.rb +5 -5
- data/lib/alchemy/on_page_layout/callbacks_runner.rb +1 -0
- data/lib/alchemy/page_layout.rb +15 -12
- data/lib/alchemy/paths.rb +1 -1
- data/lib/alchemy/permissions.rb +7 -6
- data/lib/alchemy/resource.rb +25 -15
- data/lib/alchemy/resources_helper.rb +12 -18
- data/lib/alchemy/routing_constraints.rb +1 -1
- data/lib/alchemy/seeder.rb +42 -14
- data/lib/alchemy/shell.rb +13 -10
- data/lib/alchemy/taggable.rb +1 -0
- data/lib/alchemy/tasks/tidy.rb +4 -3
- data/lib/alchemy/test_support/config_stubbing.rb +1 -0
- data/lib/alchemy/test_support/essence_shared_examples.rb +72 -72
- data/lib/alchemy/test_support/factories.rb +1 -1
- data/lib/alchemy/test_support/factories/attachment_factory.rb +5 -5
- data/lib/alchemy/test_support/factories/content_factory.rb +6 -6
- data/lib/alchemy/test_support/factories/dummy_user_factory.rb +7 -7
- data/lib/alchemy/test_support/factories/element_factory.rb +9 -9
- data/lib/alchemy/test_support/factories/essence_file_factory.rb +3 -3
- data/lib/alchemy/test_support/factories/essence_page_factory.rb +3 -3
- data/lib/alchemy/test_support/factories/essence_picture_factory.rb +4 -4
- data/lib/alchemy/test_support/factories/essence_text_factory.rb +3 -3
- data/lib/alchemy/test_support/factories/language_factory.rb +21 -14
- data/lib/alchemy/test_support/factories/node_factory.rb +8 -8
- data/lib/alchemy/test_support/factories/page_factory.rb +15 -27
- data/lib/alchemy/test_support/factories/picture_factory.rb +5 -5
- data/lib/alchemy/test_support/factories/site_factory.rb +7 -6
- data/lib/alchemy/test_support/integration_helpers.rb +1 -0
- data/lib/alchemy/test_support/shared_contexts.rb +5 -4
- data/lib/alchemy/test_support/shared_uploader_examples.rb +4 -3
- data/lib/alchemy/tinymce.rb +15 -13
- data/lib/alchemy/upgrader.rb +8 -7
- data/lib/alchemy/upgrader/five_point_zero.rb +41 -0
- data/lib/alchemy/upgrader/tasks/element_views_updater.rb +4 -4
- data/lib/alchemy/upgrader/tasks/harden_gutentag_migrations.rb +29 -0
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy_cms.rb +52 -50
- data/lib/{rails/generators → generators}/alchemy/base.rb +5 -4
- data/lib/{rails/generators → generators}/alchemy/elements/elements_generator.rb +13 -9
- data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.erb +0 -0
- data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.haml +0 -0
- data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.slim +0 -0
- data/lib/{rails/generators → generators}/alchemy/essence/essence_generator.rb +15 -13
- data/lib/generators/alchemy/essence/templates/editor.html.erb +17 -0
- data/lib/{rails/generators → generators}/alchemy/essence/templates/view.html.erb +0 -0
- data/lib/{rails/generators → generators}/alchemy/install/files/_article.html.erb +0 -0
- data/lib/{rails/generators → generators}/alchemy/install/files/_standard.html.erb +0 -0
- data/lib/{rails/generators → generators}/alchemy/install/files/alchemy.en.yml +0 -0
- data/lib/generators/alchemy/install/files/alchemy_admin.js +1 -0
- data/lib/{rails/generators → generators}/alchemy/install/files/all.css +0 -0
- data/lib/{rails/generators → generators}/alchemy/install/files/all.js +0 -0
- data/lib/{rails/generators → generators}/alchemy/install/files/application.html.erb +0 -0
- data/lib/{rails/generators → generators}/alchemy/install/files/article.scss +0 -0
- data/lib/generators/alchemy/install/install_generator.rb +169 -0
- data/lib/{rails/generators → generators}/alchemy/install/templates/dragonfly.rb.tt +0 -0
- data/lib/{rails/generators → generators}/alchemy/install/templates/elements.yml.tt +0 -0
- data/lib/{rails/generators → generators}/alchemy/install/templates/menus.yml.tt +0 -0
- data/lib/{rails/generators → generators}/alchemy/install/templates/page_layouts.yml.tt +0 -0
- data/lib/{rails/generators → generators}/alchemy/menus/menus_generator.rb +2 -2
- data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.erb +1 -4
- data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.haml +1 -4
- data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.slim +1 -4
- data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.erb +1 -1
- data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.haml +1 -1
- data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.slim +1 -1
- data/lib/{rails/generators → generators}/alchemy/module/module_generator.rb +3 -2
- data/lib/{rails/generators → generators}/alchemy/module/templates/ability.rb.tt +0 -0
- data/lib/{rails/generators → generators}/alchemy/module/templates/controller.rb.tt +0 -0
- data/lib/{rails/generators → generators}/alchemy/module/templates/module_config.rb.tt +0 -0
- data/lib/{rails/generators → generators}/alchemy/page_layouts/page_layouts_generator.rb +5 -4
- data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.erb +0 -0
- data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.haml +0 -0
- data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.slim +0 -0
- data/lib/{rails/generators → generators}/alchemy/site_layouts/site_layouts_generator.rb +4 -2
- data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.erb +0 -0
- data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.haml +0 -0
- data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.slim +0 -0
- data/lib/{rails/generators → generators}/alchemy/views/views_generator.rb +7 -6
- data/lib/kaminari/scoped_pagination_url_helper.rb +1 -0
- data/lib/tasks/alchemy/db.rake +3 -19
- data/lib/tasks/alchemy/install.rake +5 -48
- data/lib/tasks/alchemy/tidy.rake +9 -8
- data/lib/tasks/alchemy/upgrade.rake +18 -116
- data/package.json +45 -0
- data/package/admin.js +14 -0
- data/package/src/__tests__/i18n.spec.js +70 -0
- data/package/src/i18n.js +48 -0
- data/package/src/node_tree.js +72 -0
- data/package/src/translations.js +32 -0
- data/package/src/utils/__tests__/ajax.spec.js +124 -0
- data/package/src/utils/__tests__/events.spec.js +38 -0
- data/package/src/utils/ajax.js +48 -0
- data/package/src/utils/events.js +16 -0
- data/vendor/assets/fonts/fa-regular-400.eot +0 -0
- data/vendor/assets/fonts/fa-regular-400.svg +798 -358
- data/vendor/assets/fonts/fa-regular-400.ttf +0 -0
- data/vendor/assets/fonts/fa-regular-400.woff +0 -0
- data/vendor/assets/fonts/fa-regular-400.woff2 +0 -0
- data/vendor/assets/fonts/fa-solid-900.eot +0 -0
- data/vendor/assets/fonts/fa-solid-900.svg +4933 -1408
- data/vendor/assets/fonts/fa-solid-900.ttf +0 -0
- data/vendor/assets/fonts/fa-solid-900.woff +0 -0
- data/vendor/assets/fonts/fa-solid-900.woff2 +0 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +1 -2
- data/vendor/assets/stylesheets/fontawesome/_core.scss +5 -0
- data/vendor/assets/stylesheets/fontawesome/_fixed-width.scss +1 -1
- data/vendor/assets/stylesheets/fontawesome/_icons.scss +651 -2
- data/vendor/assets/stylesheets/fontawesome/_mixins.scss +0 -1
- data/vendor/assets/stylesheets/fontawesome/_rotated-flipped.scss +3 -2
- data/vendor/assets/stylesheets/fontawesome/_stacked.scss +1 -1
- data/vendor/assets/stylesheets/fontawesome/_variables.scss +662 -9
- data/vendor/assets/stylesheets/fontawesome/fontawesome.scss +2 -2
- data/vendor/assets/stylesheets/fontawesome/regular.scss +23 -0
- data/vendor/assets/stylesheets/fontawesome/solid.scss +24 -0
- metadata +112 -88
- data/app/assets/javascripts/alchemy/alchemy.i18n.js.coffee +0 -32
- data/app/assets/javascripts/alchemy/alchemy.node_tree.js +0 -66
- data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +0 -29
- data/app/assets/javascripts/alchemy/alchemy.utils.js +0 -45
- data/app/helpers/alchemy/essences_helper.rb +0 -119
- data/app/models/concerns/alchemy/content_touching.rb +0 -23
- data/app/serializers/alchemy/legacy_element_serializer.rb +0 -15
- data/app/views/alchemy/admin/contents/_missing.html.erb +0 -17
- data/app/views/alchemy/admin/pages/_menu_fields.html.erb +0 -37
- data/app/views/alchemy/admin/pages/configure_external.html.erb +0 -32
- data/app/views/alchemy/elements/_editor_not_found.html.erb +0 -4
- data/app/views/alchemy/navigation/_image_link.html.erb +0 -14
- data/app/views/alchemy/navigation/_link.html.erb +0 -19
- data/app/views/alchemy/navigation/_renderer.html.erb +0 -29
- data/db/migrate/20180226123013_alchemy_four_point_zero.rb +0 -363
- data/db/migrate/20180227224537_migrate_tags_to_gutentag.rb +0 -41
- data/db/migrate/20180519204655_add_fixed_to_alchemy_elements.rb +0 -6
- data/db/migrate/20191016073858_create_alchemy_essence_pages.rb +0 -8
- data/db/migrate/20191029212236_create_alchemy_nodes.rb +0 -24
- data/db/migrate/20200226081535_add_site_id_to_alchemy_nodes.rb +0 -15
- data/lib/alchemy/ssl_protection.rb +0 -34
- data/lib/alchemy/tasks/helpers.rb +0 -81
- data/lib/alchemy/test_support/controller_requests.rb +0 -93
- data/lib/alchemy/upgrader/four_point_four.rb +0 -52
- data/lib/alchemy/upgrader/four_point_one.rb +0 -42
- data/lib/alchemy/upgrader/four_point_six.rb +0 -50
- data/lib/alchemy/upgrader/four_point_two.rb +0 -85
- data/lib/alchemy/upgrader/tasks/cells_migration.rb +0 -43
- data/lib/alchemy/upgrader/tasks/cells_upgrader.rb +0 -148
- data/lib/alchemy/upgrader/tasks/element_partial_name_variable_updater.rb +0 -28
- data/lib/alchemy/upgrader/tasks/harden_acts_as_taggable_on_migrations.rb +0 -27
- data/lib/alchemy/upgrader/tasks/picture_gallery_migration.rb +0 -65
- data/lib/alchemy/upgrader/tasks/picture_gallery_upgrader.rb +0 -210
- data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +0 -15
- data/lib/rails/generators/alchemy/install/install_generator.rb +0 -60
- data/lib/tasks/alchemy/convert.rake +0 -97
- data/vendor/assets/javascripts/sortable/Sortable.min.js +0 -2
- data/vendor/assets/stylesheets/fontawesome/fa-regular.scss +0 -22
- data/vendor/assets/stylesheets/fontawesome/fa-solid.scss +0 -23
|
@@ -18,19 +18,20 @@ module Alchemy
|
|
|
18
18
|
|
|
19
19
|
# Returns the correct params-hash for passing to show_page_path
|
|
20
20
|
def show_page_path_params(page, optional_params = {})
|
|
21
|
-
raise ArgumentError,
|
|
21
|
+
raise ArgumentError, "Page is nil" if page.nil?
|
|
22
|
+
|
|
22
23
|
url_params = {urlname: page.urlname}.update(optional_params)
|
|
23
24
|
prefix_locale? ? url_params.update(locale: page.language_code) : url_params
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
# Returns the path for downloading an alchemy attachment
|
|
27
28
|
def download_alchemy_attachment_path(attachment)
|
|
28
|
-
alchemy.download_attachment_path(attachment, attachment.
|
|
29
|
+
alchemy.download_attachment_path(attachment, attachment.slug)
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
# Returns the url for downloading an alchemy attachment
|
|
32
33
|
def download_alchemy_attachment_url(attachment)
|
|
33
|
-
alchemy.download_attachment_url(attachment, attachment.
|
|
34
|
+
alchemy.download_attachment_url(attachment, attachment.slug)
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
# Returns the full url containing host, page and anchor for the given element
|
|
@@ -22,7 +22,7 @@ module Alchemy
|
|
|
22
22
|
include Alchemy::Filetypes
|
|
23
23
|
include Alchemy::NameConversions
|
|
24
24
|
include Alchemy::Taggable
|
|
25
|
-
include Alchemy::
|
|
25
|
+
include Alchemy::TouchElements
|
|
26
26
|
|
|
27
27
|
dragonfly_accessor :file, app: :alchemy_attachments do
|
|
28
28
|
after_assign { |f| write_attribute(:file_mime_type, f.mime_type) }
|
|
@@ -30,7 +30,7 @@ module Alchemy
|
|
|
30
30
|
|
|
31
31
|
stampable stamper_class_name: Alchemy.user_class_name
|
|
32
32
|
|
|
33
|
-
has_many :essence_files, class_name:
|
|
33
|
+
has_many :essence_files, class_name: "Alchemy::EssenceFile", foreign_key: "attachment_id"
|
|
34
34
|
has_many :contents, through: :essence_files
|
|
35
35
|
has_many :elements, through: :contents
|
|
36
36
|
has_many :pages, through: :elements
|
|
@@ -42,24 +42,25 @@ module Alchemy
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def allowed_filetypes
|
|
45
|
-
Config.get(:uploader).fetch(
|
|
45
|
+
Config.get(:uploader).fetch("allowed_filetypes", {}).fetch("alchemy/attachments", [])
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def file_types_for_select
|
|
49
49
|
file_types = Alchemy::Attachment.pluck(:file_mime_type).uniq.map do |type|
|
|
50
|
-
[Alchemy.t(type, scope:
|
|
50
|
+
[Alchemy.t(type, scope: "mime_types"), type]
|
|
51
51
|
end
|
|
52
52
|
file_types.sort_by(&:first)
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
validates_presence_of :file
|
|
57
|
-
validates_size_of :file, maximum: Config.get(:uploader)[
|
|
58
|
-
validates_property :ext,
|
|
57
|
+
validates_size_of :file, maximum: Config.get(:uploader)["file_size_limit"].megabytes
|
|
58
|
+
validates_property :ext,
|
|
59
|
+
of: :file,
|
|
59
60
|
in: allowed_filetypes,
|
|
60
61
|
case_sensitive: false,
|
|
61
62
|
message: Alchemy.t("not a valid file"),
|
|
62
|
-
unless: -> { self.class.allowed_filetypes.include?(
|
|
63
|
+
unless: -> { self.class.allowed_filetypes.include?("*") }
|
|
63
64
|
|
|
64
65
|
before_save :set_name, if: :file_name_changed?
|
|
65
66
|
|
|
@@ -71,15 +72,18 @@ module Alchemy
|
|
|
71
72
|
{
|
|
72
73
|
"name" => read_attribute(:file_name),
|
|
73
74
|
"size" => read_attribute(:file_size),
|
|
74
|
-
|
|
75
|
+
"error" => errors[:file].join,
|
|
75
76
|
}
|
|
76
77
|
end
|
|
77
78
|
|
|
78
79
|
# An url save filename without format suffix
|
|
79
|
-
def
|
|
80
|
-
CGI.escape(file_name.gsub(/\.#{extension}$/,
|
|
80
|
+
def slug
|
|
81
|
+
CGI.escape(file_name.gsub(/\.#{extension}$/, "").tr(".", " "))
|
|
81
82
|
end
|
|
82
83
|
|
|
84
|
+
alias_method :urlname, :slug
|
|
85
|
+
deprecate urlname: :slug, deprecator: Alchemy::Deprecation
|
|
86
|
+
|
|
83
87
|
# Checks if the attachment is restricted, because it is attached on restricted pages only
|
|
84
88
|
def restricted?
|
|
85
89
|
pages.any? && pages.not_restricted.blank?
|
|
@@ -89,6 +93,7 @@ module Alchemy
|
|
|
89
93
|
def extension
|
|
90
94
|
file_name.split(".").last
|
|
91
95
|
end
|
|
96
|
+
|
|
92
97
|
alias_method :suffix, :extension
|
|
93
98
|
|
|
94
99
|
# Returns a css class name for kind of file
|
|
@@ -96,23 +101,23 @@ module Alchemy
|
|
|
96
101
|
def icon_css_class
|
|
97
102
|
case file_mime_type
|
|
98
103
|
when "application/pdf"
|
|
99
|
-
|
|
104
|
+
"file-pdf"
|
|
100
105
|
when "application/msword"
|
|
101
|
-
|
|
106
|
+
"file-word"
|
|
102
107
|
when *TEXT_FILE_TYPES
|
|
103
|
-
|
|
108
|
+
"file-alt"
|
|
104
109
|
when *EXCEL_FILE_TYPES
|
|
105
|
-
|
|
110
|
+
"file-excel"
|
|
106
111
|
when *VCARD_FILE_TYPES
|
|
107
|
-
|
|
112
|
+
"address-card"
|
|
108
113
|
when *ARCHIVE_FILE_TYPES
|
|
109
|
-
|
|
114
|
+
"file-archive"
|
|
110
115
|
when *AUDIO_FILE_TYPES
|
|
111
|
-
|
|
116
|
+
"file-audio"
|
|
112
117
|
when *IMAGE_FILE_TYPES
|
|
113
|
-
|
|
118
|
+
"file-image"
|
|
114
119
|
when *VIDEO_FILE_TYPES
|
|
115
|
-
|
|
120
|
+
"file-video"
|
|
116
121
|
else
|
|
117
122
|
"file"
|
|
118
123
|
end
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Alchemy
|
|
2
3
|
def self.table_name_prefix
|
|
3
|
-
|
|
4
|
+
"alchemy_"
|
|
4
5
|
end
|
|
5
6
|
|
|
6
7
|
class BaseRecord < ActiveRecord::Base
|
|
7
8
|
self.abstract_class = true
|
|
8
|
-
|
|
9
|
-
def active_record_5_1?
|
|
10
|
-
ActiveRecord.gem_version >= Gem::Version.new('5.1.0')
|
|
11
|
-
end
|
|
12
9
|
end
|
|
13
10
|
end
|
|
@@ -28,29 +28,25 @@ module Alchemy
|
|
|
28
28
|
belongs_to :element, touch: true, inverse_of: :contents
|
|
29
29
|
has_one :page, through: :element
|
|
30
30
|
|
|
31
|
-
stampable stamper_class_name: Alchemy.user_class_name
|
|
32
|
-
|
|
33
|
-
acts_as_list scope: [:element_id]
|
|
34
|
-
|
|
35
31
|
# Essence scopes
|
|
36
|
-
scope :essence_booleans,
|
|
37
|
-
scope :essence_dates,
|
|
38
|
-
scope :essence_files,
|
|
39
|
-
scope :essence_htmls,
|
|
40
|
-
scope :essence_links,
|
|
41
|
-
scope :essence_pictures,
|
|
32
|
+
scope :essence_booleans, -> { where(essence_type: "Alchemy::EssenceBoolean") }
|
|
33
|
+
scope :essence_dates, -> { where(essence_type: "Alchemy::EssenceDate") }
|
|
34
|
+
scope :essence_files, -> { where(essence_type: "Alchemy::EssenceFile") }
|
|
35
|
+
scope :essence_htmls, -> { where(essence_type: "Alchemy::EssenceHtml") }
|
|
36
|
+
scope :essence_links, -> { where(essence_type: "Alchemy::EssenceLink") }
|
|
37
|
+
scope :essence_pictures, -> { where(essence_type: "Alchemy::EssencePicture") }
|
|
42
38
|
scope :essence_richtexts, -> { where(essence_type: "Alchemy::EssenceRichtext") }
|
|
43
|
-
scope :essence_selects,
|
|
44
|
-
scope :essence_texts,
|
|
45
|
-
scope :named,
|
|
46
|
-
scope :available,
|
|
47
|
-
scope :published,
|
|
48
|
-
scope :not_trashed,
|
|
49
|
-
scope :not_restricted,
|
|
50
|
-
|
|
51
|
-
delegate :restricted?, to: :page,
|
|
52
|
-
delegate :trashed?,
|
|
53
|
-
delegate :public?,
|
|
39
|
+
scope :essence_selects, -> { where(essence_type: "Alchemy::EssenceSelect") }
|
|
40
|
+
scope :essence_texts, -> { where(essence_type: "Alchemy::EssenceText") }
|
|
41
|
+
scope :named, ->(name) { where(name: name) }
|
|
42
|
+
scope :available, -> { published.not_trashed }
|
|
43
|
+
scope :published, -> { joins(:element).merge(Element.published) }
|
|
44
|
+
scope :not_trashed, -> { joins(:element).merge(Element.not_trashed) }
|
|
45
|
+
scope :not_restricted, -> { joins(:element).merge(Element.not_restricted) }
|
|
46
|
+
|
|
47
|
+
delegate :restricted?, to: :page, allow_nil: true
|
|
48
|
+
delegate :trashed?, to: :element, allow_nil: true
|
|
49
|
+
delegate :public?, to: :element, allow_nil: true
|
|
54
50
|
|
|
55
51
|
class << self
|
|
56
52
|
# Returns the translated label for a content name.
|
|
@@ -72,7 +68,7 @@ module Alchemy
|
|
|
72
68
|
Alchemy.t(
|
|
73
69
|
content_name,
|
|
74
70
|
scope: "content_names.#{element_name}",
|
|
75
|
-
default: Alchemy.t("content_names.#{content_name}", default: content_name.humanize)
|
|
71
|
+
default: Alchemy.t("content_names.#{content_name}", default: content_name.humanize),
|
|
76
72
|
)
|
|
77
73
|
end
|
|
78
74
|
end
|
|
@@ -99,6 +95,7 @@ module Alchemy
|
|
|
99
95
|
# Settings from the elements.yml definition
|
|
100
96
|
def settings
|
|
101
97
|
return {} if definition.blank?
|
|
98
|
+
|
|
102
99
|
@settings ||= definition.fetch(:settings, {})
|
|
103
100
|
end
|
|
104
101
|
|
|
@@ -114,12 +111,14 @@ module Alchemy
|
|
|
114
111
|
|
|
115
112
|
def siblings
|
|
116
113
|
return [] if !element
|
|
114
|
+
|
|
117
115
|
element.contents
|
|
118
116
|
end
|
|
119
117
|
|
|
120
118
|
# Gets the ingredient from essence
|
|
121
119
|
def ingredient
|
|
122
120
|
return nil if essence.nil?
|
|
121
|
+
|
|
123
122
|
essence.ingredient
|
|
124
123
|
end
|
|
125
124
|
|
|
@@ -129,7 +128,7 @@ module Alchemy
|
|
|
129
128
|
{
|
|
130
129
|
name: name,
|
|
131
130
|
value: serialized_ingredient,
|
|
132
|
-
link: essence.try(:link)
|
|
131
|
+
link: essence.try(:link),
|
|
133
132
|
}.delete_if { |_k, v| v.blank? }
|
|
134
133
|
end
|
|
135
134
|
|
|
@@ -145,6 +144,7 @@ module Alchemy
|
|
|
145
144
|
# Sets the ingredient from essence
|
|
146
145
|
def ingredient=(value)
|
|
147
146
|
raise EssenceMissingError if essence.nil?
|
|
147
|
+
|
|
148
148
|
essence.ingredient = value
|
|
149
149
|
end
|
|
150
150
|
|
|
@@ -156,11 +156,12 @@ module Alchemy
|
|
|
156
156
|
#
|
|
157
157
|
def update_essence(params = {})
|
|
158
158
|
raise EssenceMissingError if essence.nil?
|
|
159
|
+
|
|
159
160
|
if essence.update(params)
|
|
160
|
-
|
|
161
|
+
true
|
|
161
162
|
else
|
|
162
163
|
errors.add(:essence, :validation_failed)
|
|
163
|
-
|
|
164
|
+
false
|
|
164
165
|
end
|
|
165
166
|
end
|
|
166
167
|
|
|
@@ -169,12 +170,13 @@ module Alchemy
|
|
|
169
170
|
end
|
|
170
171
|
|
|
171
172
|
def has_validations?
|
|
172
|
-
definition[
|
|
173
|
+
definition["validate"].present?
|
|
173
174
|
end
|
|
174
175
|
|
|
175
176
|
# Returns a string used as dom id on html elements.
|
|
176
177
|
def dom_id
|
|
177
|
-
return
|
|
178
|
+
return "" if essence.nil?
|
|
179
|
+
|
|
178
180
|
"#{essence_partial_name}_#{id}"
|
|
179
181
|
end
|
|
180
182
|
|
|
@@ -189,7 +191,7 @@ module Alchemy
|
|
|
189
191
|
|
|
190
192
|
# Returns true if this content should be taken for element preview.
|
|
191
193
|
def preview_content?
|
|
192
|
-
!!definition[
|
|
194
|
+
!!definition["as_element_title"]
|
|
193
195
|
end
|
|
194
196
|
|
|
195
197
|
# Proxy method that returns the preview text from essence.
|
|
@@ -199,7 +201,8 @@ module Alchemy
|
|
|
199
201
|
end
|
|
200
202
|
|
|
201
203
|
def essence_partial_name
|
|
202
|
-
return
|
|
204
|
+
return "" if essence.nil?
|
|
205
|
+
|
|
203
206
|
essence.partial_name
|
|
204
207
|
end
|
|
205
208
|
|
|
@@ -223,19 +226,11 @@ module Alchemy
|
|
|
223
226
|
"has_tinymce" + (has_custom_tinymce_config? ? " #{element.name}_#{name}" : "")
|
|
224
227
|
end
|
|
225
228
|
|
|
226
|
-
def editor
|
|
227
|
-
@_editor ||= ContentEditor.new(self)
|
|
228
|
-
end
|
|
229
|
-
delegate :form_field_name, to: :editor
|
|
230
|
-
deprecate form_field_name: "use Alchemy::ContentEditor#form_field_name instead", deprecator: Alchemy::Deprecation
|
|
231
|
-
delegate :form_field_id, to: :editor
|
|
232
|
-
deprecate form_field_id: "use Alchemy::ContentEditor#form_field_id instead", deprecator: Alchemy::Deprecation
|
|
233
|
-
|
|
234
229
|
# Returns the default value from content definition
|
|
235
230
|
#
|
|
236
231
|
# If the value is a symbol it gets passed through i18n
|
|
237
232
|
# inside the +alchemy.default_content_texts+ scope
|
|
238
|
-
def
|
|
233
|
+
def default_value(default = definition[:default])
|
|
239
234
|
case default
|
|
240
235
|
when Symbol
|
|
241
236
|
Alchemy.t(default, scope: :default_content_texts)
|
|
@@ -22,10 +22,13 @@ module Alchemy
|
|
|
22
22
|
if definition.blank?
|
|
23
23
|
raise ContentDefinitionError, "No definition found in elements.yml for #{attributes.inspect} and #{element.inspect}"
|
|
24
24
|
end
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
super(
|
|
27
|
+
name: definition[:name],
|
|
28
|
+
essence_type: normalize_essence_type(definition[:type]),
|
|
29
|
+
element_id: element.id
|
|
30
|
+
).tap(&:build_essence)
|
|
26
31
|
end
|
|
27
|
-
alias_method :build, :new
|
|
28
|
-
deprecate build: :new, deprecator: Alchemy::Deprecation
|
|
29
32
|
|
|
30
33
|
# Creates a new content from elements definition in the +elements.yml+ file.
|
|
31
34
|
#
|
|
@@ -34,20 +37,11 @@ module Alchemy
|
|
|
34
37
|
#
|
|
35
38
|
# @return [Alchemy::Content]
|
|
36
39
|
#
|
|
37
|
-
def create(
|
|
38
|
-
attributes
|
|
39
|
-
|
|
40
|
-
Alchemy::Deprecation.warn 'Passing an element as first argument to Alchemy::Content.create is deprecated! Pass an attribute hash with element inside instead.'
|
|
41
|
-
element = args.first
|
|
42
|
-
else
|
|
43
|
-
element = attributes[:element]
|
|
44
|
-
end
|
|
45
|
-
new(attributes.merge(element: element)).tap do |content|
|
|
46
|
-
content.create_essence!(attributes[:essence_type])
|
|
40
|
+
def create(attributes = {})
|
|
41
|
+
new(attributes).tap do |content|
|
|
42
|
+
content.essence.save && content.save
|
|
47
43
|
end
|
|
48
44
|
end
|
|
49
|
-
alias_method :create_from_scratch, :create
|
|
50
|
-
deprecate create_from_scratch: :create, deprecator: Alchemy::Deprecation
|
|
51
45
|
|
|
52
46
|
# Creates a copy of source and also copies the associated essence.
|
|
53
47
|
#
|
|
@@ -62,11 +56,11 @@ module Alchemy
|
|
|
62
56
|
new_content = Content.new(
|
|
63
57
|
source.attributes.
|
|
64
58
|
except(*SKIPPED_ATTRIBUTES_ON_COPY).
|
|
65
|
-
merge(differences.with_indifferent_access)
|
|
59
|
+
merge(differences.with_indifferent_access),
|
|
66
60
|
)
|
|
67
61
|
new_essence = source.essence.class.create!(
|
|
68
62
|
source.essence.attributes.
|
|
69
|
-
except(*SKIPPED_ATTRIBUTES_ON_COPY)
|
|
63
|
+
except(*SKIPPED_ATTRIBUTES_ON_COPY),
|
|
70
64
|
)
|
|
71
65
|
new_content.tap do |content|
|
|
72
66
|
content.essence = new_essence
|
|
@@ -77,7 +71,7 @@ module Alchemy
|
|
|
77
71
|
# Returns all content definitions from elements.yml
|
|
78
72
|
#
|
|
79
73
|
def definitions
|
|
80
|
-
definitions = Element.definitions.flat_map { |e| e[
|
|
74
|
+
definitions = Element.definitions.flat_map { |e| e["contents"] }
|
|
81
75
|
definitions.compact!
|
|
82
76
|
definitions
|
|
83
77
|
end
|
|
@@ -119,12 +113,22 @@ module Alchemy
|
|
|
119
113
|
element.content_definition_for(name) || {}
|
|
120
114
|
end
|
|
121
115
|
|
|
116
|
+
# Build essence from definition.
|
|
117
|
+
#
|
|
118
|
+
# If an optional type is passed, this type of essence gets created.
|
|
119
|
+
#
|
|
120
|
+
def build_essence(type = essence_type)
|
|
121
|
+
self.essence = essence_class(type).new({
|
|
122
|
+
ingredient: default_value,
|
|
123
|
+
})
|
|
124
|
+
end
|
|
125
|
+
|
|
122
126
|
# Creates essence from definition.
|
|
123
127
|
#
|
|
124
128
|
# If an optional type is passed, this type of essence gets created.
|
|
125
129
|
#
|
|
126
130
|
def create_essence!(type = nil)
|
|
127
|
-
|
|
131
|
+
build_essence(type).save!
|
|
128
132
|
save!
|
|
129
133
|
end
|
|
130
134
|
|
|
@@ -135,18 +139,7 @@ module Alchemy
|
|
|
135
139
|
# If an optional type is passed, this type of essence gets constantized.
|
|
136
140
|
#
|
|
137
141
|
def essence_class(type = nil)
|
|
138
|
-
Content.normalize_essence_type(type || definition[
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# Prepares the attributes for creating the essence.
|
|
142
|
-
#
|
|
143
|
-
# 1. It sets a default text if given in +elements.yml+
|
|
144
|
-
#
|
|
145
|
-
def prepared_attributes_for_essence
|
|
146
|
-
attributes = {
|
|
147
|
-
ingredient: default_text(definition['default'])
|
|
148
|
-
}
|
|
149
|
-
attributes
|
|
142
|
+
Content.normalize_essence_type(type || definition["type"]).constantize
|
|
150
143
|
end
|
|
151
144
|
end
|
|
152
145
|
end
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
|
|
23
23
|
module Alchemy
|
|
24
24
|
class Element < BaseRecord
|
|
25
|
+
NAME_REGEXP = /\A[a-z0-9_-]+\z/
|
|
26
|
+
|
|
25
27
|
include Alchemy::Logger
|
|
26
28
|
include Alchemy::Taggable
|
|
27
29
|
include Alchemy::Hints
|
|
@@ -34,7 +36,7 @@ module Alchemy
|
|
|
34
36
|
"hint",
|
|
35
37
|
"taggable",
|
|
36
38
|
"compact",
|
|
37
|
-
"message"
|
|
39
|
+
"message",
|
|
38
40
|
].freeze
|
|
39
41
|
|
|
40
42
|
SKIPPED_ATTRIBUTES_ON_COPY = [
|
|
@@ -45,7 +47,7 @@ module Alchemy
|
|
|
45
47
|
"folded",
|
|
46
48
|
"position",
|
|
47
49
|
"updated_at",
|
|
48
|
-
"updater_id"
|
|
50
|
+
"updater_id",
|
|
49
51
|
].freeze
|
|
50
52
|
|
|
51
53
|
# All Elements that share the same page id and parent element id and are fixed or not are considered a list.
|
|
@@ -60,17 +62,17 @@ module Alchemy
|
|
|
60
62
|
|
|
61
63
|
stampable stamper_class_name: Alchemy.user_class_name
|
|
62
64
|
|
|
63
|
-
has_many :contents,
|
|
65
|
+
has_many :contents, dependent: :destroy, inverse_of: :element
|
|
64
66
|
|
|
65
67
|
has_many :all_nested_elements,
|
|
66
68
|
-> { order(:position).not_trashed },
|
|
67
|
-
class_name:
|
|
69
|
+
class_name: "Alchemy::Element",
|
|
68
70
|
foreign_key: :parent_element_id,
|
|
69
71
|
dependent: :destroy
|
|
70
72
|
|
|
71
73
|
has_many :nested_elements,
|
|
72
74
|
-> { order(:position).available },
|
|
73
|
-
class_name:
|
|
75
|
+
class_name: "Alchemy::Element",
|
|
74
76
|
foreign_key: :parent_element_id,
|
|
75
77
|
dependent: :destroy,
|
|
76
78
|
inverse_of: :parent_element
|
|
@@ -79,17 +81,17 @@ module Alchemy
|
|
|
79
81
|
|
|
80
82
|
# A nested element belongs to a parent element.
|
|
81
83
|
belongs_to :parent_element,
|
|
82
|
-
class_name:
|
|
84
|
+
class_name: "Alchemy::Element",
|
|
83
85
|
optional: true,
|
|
84
86
|
touch: true,
|
|
85
87
|
inverse_of: :nested_elements
|
|
86
88
|
|
|
87
89
|
has_and_belongs_to_many :touchable_pages, -> { distinct },
|
|
88
|
-
class_name:
|
|
90
|
+
class_name: "Alchemy::Page",
|
|
89
91
|
join_table: ElementToPage.table_name
|
|
90
92
|
|
|
91
93
|
validates_presence_of :name, on: :create
|
|
92
|
-
validates_format_of :name, on: :create, with:
|
|
94
|
+
validates_format_of :name, on: :create, with: NAME_REGEXP
|
|
93
95
|
|
|
94
96
|
attr_accessor :autogenerate_contents
|
|
95
97
|
attr_accessor :autogenerate_nested_elements
|
|
@@ -98,19 +100,19 @@ module Alchemy
|
|
|
98
100
|
|
|
99
101
|
after_update :touch_touchable_pages
|
|
100
102
|
|
|
101
|
-
scope :trashed,
|
|
102
|
-
scope :not_trashed,
|
|
103
|
-
scope :published,
|
|
104
|
-
scope :not_restricted,
|
|
105
|
-
scope :available,
|
|
106
|
-
scope :named,
|
|
107
|
-
scope :excluded,
|
|
108
|
-
scope :fixed,
|
|
109
|
-
scope :unfixed,
|
|
110
|
-
scope :from_current_site, -> { where(Language.table_name => {site_id: Site.current || Site.default}).joins(page:
|
|
111
|
-
scope :folded,
|
|
112
|
-
scope :expanded,
|
|
113
|
-
scope :not_nested,
|
|
103
|
+
scope :trashed, -> { where(position: nil).order("updated_at DESC") }
|
|
104
|
+
scope :not_trashed, -> { where.not(position: nil) }
|
|
105
|
+
scope :published, -> { where(public: true) }
|
|
106
|
+
scope :not_restricted, -> { joins(:page).merge(Page.not_restricted) }
|
|
107
|
+
scope :available, -> { published.not_trashed }
|
|
108
|
+
scope :named, ->(names) { where(name: names) }
|
|
109
|
+
scope :excluded, ->(names) { where.not(name: names) }
|
|
110
|
+
scope :fixed, -> { where(fixed: true) }
|
|
111
|
+
scope :unfixed, -> { where(fixed: false) }
|
|
112
|
+
scope :from_current_site, -> { where(Language.table_name => { site_id: Site.current || Site.default }).joins(page: "language") }
|
|
113
|
+
scope :folded, -> { where(folded: true) }
|
|
114
|
+
scope :expanded, -> { where(folded: false) }
|
|
115
|
+
scope :not_nested, -> { where(parent_element_id: nil) }
|
|
114
116
|
|
|
115
117
|
delegate :restricted?, to: :page, allow_nil: true
|
|
116
118
|
|
|
@@ -131,7 +133,8 @@ module Alchemy
|
|
|
131
133
|
#
|
|
132
134
|
def new(attributes = {})
|
|
133
135
|
return super if attributes[:name].blank?
|
|
134
|
-
|
|
136
|
+
|
|
137
|
+
element_attributes = attributes.to_h.merge(name: attributes[:name].split("#").first)
|
|
135
138
|
element_definition = Element.definition_by_name(element_attributes[:name])
|
|
136
139
|
if element_definition.nil?
|
|
137
140
|
raise(ElementDefinitionError, attributes)
|
|
@@ -139,11 +142,6 @@ module Alchemy
|
|
|
139
142
|
|
|
140
143
|
super(element_definition.merge(element_attributes).except(*FORBIDDEN_DEFINITION_ATTRIBUTES))
|
|
141
144
|
end
|
|
142
|
-
alias_method :new_from_scratch, :new
|
|
143
|
-
deprecate new_from_scratch: :new, deprecator: Alchemy::Deprecation
|
|
144
|
-
|
|
145
|
-
alias_method :create_from_scratch, :create
|
|
146
|
-
deprecate create_from_scratch: :create, deprecator: Alchemy::Deprecation
|
|
147
145
|
|
|
148
146
|
# This methods does a copy of source and all depending contents and all of their depending essences.
|
|
149
147
|
#
|
|
@@ -158,13 +156,13 @@ module Alchemy
|
|
|
158
156
|
#
|
|
159
157
|
def copy(source_element, differences = {})
|
|
160
158
|
attributes = source_element.attributes.with_indifferent_access
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
159
|
+
.except(*SKIPPED_ATTRIBUTES_ON_COPY)
|
|
160
|
+
.merge(differences)
|
|
161
|
+
.merge({
|
|
162
|
+
autogenerate_contents: false,
|
|
163
|
+
autogenerate_nested_elements: false,
|
|
164
|
+
tag_list: source_element.tag_list,
|
|
165
|
+
})
|
|
168
166
|
|
|
169
167
|
new_element = create!(attributes)
|
|
170
168
|
|
|
@@ -181,13 +179,15 @@ module Alchemy
|
|
|
181
179
|
|
|
182
180
|
def all_from_clipboard(clipboard)
|
|
183
181
|
return [] if clipboard.nil?
|
|
184
|
-
|
|
182
|
+
|
|
183
|
+
where(id: clipboard.collect { |e| e["id"] })
|
|
185
184
|
end
|
|
186
185
|
|
|
187
186
|
# All elements in clipboard that could be placed on page
|
|
188
187
|
#
|
|
189
188
|
def all_from_clipboard_for_page(clipboard, page)
|
|
190
189
|
return [] if clipboard.nil? || page.nil?
|
|
190
|
+
|
|
191
191
|
all_from_clipboard(clipboard).select { |ce|
|
|
192
192
|
page.available_element_names.include?(ce.name)
|
|
193
193
|
}
|
|
@@ -199,7 +199,7 @@ module Alchemy
|
|
|
199
199
|
# Pass an element name to get next of this kind.
|
|
200
200
|
#
|
|
201
201
|
def next(name = nil)
|
|
202
|
-
elements = page.elements.published.where(
|
|
202
|
+
elements = page.elements.published.where("position > ?", position)
|
|
203
203
|
select_element(elements, name, :asc)
|
|
204
204
|
end
|
|
205
205
|
|
|
@@ -208,13 +208,14 @@ module Alchemy
|
|
|
208
208
|
# Pass an element name to get previous of this kind.
|
|
209
209
|
#
|
|
210
210
|
def prev(name = nil)
|
|
211
|
-
elements = page.elements.published.where(
|
|
211
|
+
elements = page.elements.published.where("position < ?", position)
|
|
212
212
|
select_element(elements, name, :desc)
|
|
213
213
|
end
|
|
214
214
|
|
|
215
215
|
# Stores the page into +touchable_pages+ (Pages that have to be touched after updating the element).
|
|
216
216
|
def store_page(page)
|
|
217
217
|
return true if page.nil?
|
|
218
|
+
|
|
218
219
|
unless touchable_pages.include? page
|
|
219
220
|
touchable_pages << page
|
|
220
221
|
end
|
|
@@ -233,7 +234,7 @@ module Alchemy
|
|
|
233
234
|
|
|
234
235
|
# Returns true if the definition of this element has a taggable true value.
|
|
235
236
|
def taggable?
|
|
236
|
-
definition[
|
|
237
|
+
definition["taggable"] == true
|
|
237
238
|
end
|
|
238
239
|
|
|
239
240
|
# The opposite of folded?
|
|
@@ -243,7 +244,7 @@ module Alchemy
|
|
|
243
244
|
|
|
244
245
|
# Defined as compact element?
|
|
245
246
|
def compact?
|
|
246
|
-
definition[
|
|
247
|
+
definition["compact"] == true
|
|
247
248
|
end
|
|
248
249
|
|
|
249
250
|
# The element's view partial is dependent from its name
|
|
@@ -261,17 +262,7 @@ module Alchemy
|
|
|
261
262
|
# Element partials live in +app/views/alchemy/elements+
|
|
262
263
|
#
|
|
263
264
|
def to_partial_path
|
|
264
|
-
|
|
265
|
-
Alchemy::Deprecation.warn <<~WARN
|
|
266
|
-
Having the `_view` suffix on your element view partials is deprecated
|
|
267
|
-
and will not be supported in Alchemy 5.0 anymore. You can safely remove the suffix now.
|
|
268
|
-
|
|
269
|
-
Please also rename the local `element` or `#{name}_view` variable into `#{name}`.
|
|
270
|
-
WARN
|
|
271
|
-
"alchemy/elements/#{name}_view"
|
|
272
|
-
else
|
|
273
|
-
"alchemy/elements/#{name}"
|
|
274
|
-
end
|
|
265
|
+
"alchemy/elements/#{name}"
|
|
275
266
|
end
|
|
276
267
|
|
|
277
268
|
# Returns the key that's taken for cache path.
|
|
@@ -290,7 +281,7 @@ module Alchemy
|
|
|
290
281
|
|
|
291
282
|
# A collection of element names that can be nested inside this element.
|
|
292
283
|
def nestable_elements
|
|
293
|
-
definition.fetch(
|
|
284
|
+
definition.fetch("nestable_elements", [])
|
|
294
285
|
end
|
|
295
286
|
|
|
296
287
|
# Copy all nested elements from current element to given target element.
|
|
@@ -298,7 +289,7 @@ module Alchemy
|
|
|
298
289
|
nested_elements.map do |nested_element|
|
|
299
290
|
Element.copy(nested_element, {
|
|
300
291
|
parent_element_id: target_element.id,
|
|
301
|
-
page_id: target_element.page_id
|
|
292
|
+
page_id: target_element.page_id,
|
|
302
293
|
})
|
|
303
294
|
end
|
|
304
295
|
end
|
|
@@ -306,7 +297,7 @@ module Alchemy
|
|
|
306
297
|
private
|
|
307
298
|
|
|
308
299
|
def generate_nested_elements
|
|
309
|
-
definition.fetch(
|
|
300
|
+
definition.fetch("autogenerate", []).each do |nestable_element|
|
|
310
301
|
if nestable_elements.include?(nestable_element)
|
|
311
302
|
Element.create(page: page, parent_element_id: id, name: nestable_element)
|
|
312
303
|
else
|
|
@@ -326,6 +317,7 @@ module Alchemy
|
|
|
326
317
|
#
|
|
327
318
|
def touch_touchable_pages
|
|
328
319
|
return unless respond_to?(:touchable_pages)
|
|
320
|
+
|
|
329
321
|
touchable_pages.each(&:touch)
|
|
330
322
|
end
|
|
331
323
|
end
|