alchemy_cms 4.6.0 → 5.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- 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 +100 -0
- 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 +50 -62
- 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 +36 -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 +2 -1
- data/app/mailers/alchemy/base_mailer.rb +1 -1
- data/app/mailers/alchemy/messages_mailer.rb +1 -1
- data/app/models/alchemy/attachment.rb +20 -18
- 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 +4 -4
- 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 +17 -16
- 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 +5 -5
- 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/resources/_resource.html.erb +1 -1
- data/app/views/alchemy/admin/resources/_table.html.erb +2 -2
- 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_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 +114 -90
- 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,7 +18,8 @@ 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
|
@@ -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,13 +72,13 @@ 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
80
|
def urlname
|
80
|
-
CGI.escape(file_name.gsub(/\.#{extension}$/,
|
81
|
+
CGI.escape(file_name.gsub(/\.#{extension}$/, "").tr(".", " "))
|
81
82
|
end
|
82
83
|
|
83
84
|
# Checks if the attachment is restricted, because it is attached on restricted pages only
|
@@ -89,6 +90,7 @@ module Alchemy
|
|
89
90
|
def extension
|
90
91
|
file_name.split(".").last
|
91
92
|
end
|
93
|
+
|
92
94
|
alias_method :suffix, :extension
|
93
95
|
|
94
96
|
# Returns a css class name for kind of file
|
@@ -96,23 +98,23 @@ module Alchemy
|
|
96
98
|
def icon_css_class
|
97
99
|
case file_mime_type
|
98
100
|
when "application/pdf"
|
99
|
-
|
101
|
+
"file-pdf"
|
100
102
|
when "application/msword"
|
101
|
-
|
103
|
+
"file-word"
|
102
104
|
when *TEXT_FILE_TYPES
|
103
|
-
|
105
|
+
"file-alt"
|
104
106
|
when *EXCEL_FILE_TYPES
|
105
|
-
|
107
|
+
"file-excel"
|
106
108
|
when *VCARD_FILE_TYPES
|
107
|
-
|
109
|
+
"address-card"
|
108
110
|
when *ARCHIVE_FILE_TYPES
|
109
|
-
|
111
|
+
"file-archive"
|
110
112
|
when *AUDIO_FILE_TYPES
|
111
|
-
|
113
|
+
"file-audio"
|
112
114
|
when *IMAGE_FILE_TYPES
|
113
|
-
|
115
|
+
"file-image"
|
114
116
|
when *VIDEO_FILE_TYPES
|
115
|
-
|
117
|
+
"file-video"
|
116
118
|
else
|
117
119
|
"file"
|
118
120
|
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
|