alchemy_cms 7.0.8 → 7.1.0.pre.b2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +162 -0
- data/Gemfile +9 -11
- data/README.md +11 -9
- data/alchemy_cms.gemspec +4 -3
- data/app/assets/config/alchemy_manifest.js +3 -5
- data/app/assets/images/alchemy/missing-image.svg +1 -1
- data/app/assets/javascripts/alchemy/admin.js +1 -23
- data/app/assets/javascripts/alchemy/alchemy.confirm_dialog.js.coffee +2 -3
- data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +19 -34
- data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +38 -13
- data/app/assets/javascripts/alchemy/alchemy.file_progress.js.coffee +1 -1
- data/app/assets/javascripts/alchemy/alchemy.fixed_elements.js +32 -25
- data/app/assets/javascripts/alchemy/alchemy.growler.js.coffee +1 -1
- data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +3 -5
- data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +0 -57
- data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +24 -65
- data/app/assets/javascripts/alchemy/alchemy.list_filter.js.coffee +2 -2
- data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +5 -4
- data/app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee +5 -5
- data/app/assets/javascripts/alchemy/templates/index.js +0 -2
- data/app/assets/javascripts/alchemy/templates/node_folder.hbs +1 -1
- data/app/assets/javascripts/alchemy/templates/page.hbs +1 -1
- data/app/assets/javascripts/alchemy/templates/page_folder.hbs +2 -2
- data/app/assets/javascripts/tinymce/icons/remixicons/icons.js +93 -0
- data/app/assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js +37 -18
- data/app/assets/stylesheets/alchemy/_custom-properties.scss +82 -0
- data/app/assets/stylesheets/alchemy/_mixins.scss +38 -30
- data/app/assets/stylesheets/alchemy/_variables.scss +23 -8
- data/app/assets/stylesheets/alchemy/admin.scss +3 -4
- data/app/assets/stylesheets/alchemy/archive.scss +110 -50
- data/app/assets/stylesheets/alchemy/attachments.scss +5 -4
- data/app/assets/stylesheets/alchemy/buttons.scss +41 -166
- data/app/assets/stylesheets/alchemy/dashboard.scss +31 -6
- data/app/assets/stylesheets/alchemy/dialogs.scss +12 -28
- data/app/assets/stylesheets/alchemy/elements.scss +272 -282
- data/app/assets/stylesheets/alchemy/flash.scss +20 -12
- data/app/assets/stylesheets/alchemy/forms.scss +21 -34
- data/app/assets/stylesheets/alchemy/frame.scss +11 -32
- data/app/assets/stylesheets/alchemy/hints.scss +4 -62
- data/app/assets/stylesheets/alchemy/image_library.scss +36 -33
- data/app/assets/stylesheets/alchemy/menubar.scss +7 -6
- data/app/assets/stylesheets/alchemy/navigation.scss +27 -15
- data/app/assets/stylesheets/alchemy/nodes.scss +11 -7
- data/app/assets/stylesheets/alchemy/notices.scss +16 -4
- data/app/assets/stylesheets/alchemy/page-select.scss +10 -2
- data/app/assets/stylesheets/alchemy/pagination.scss +22 -13
- data/app/assets/stylesheets/alchemy/resource_info.scss +7 -5
- data/app/assets/stylesheets/alchemy/selects.scss +49 -42
- data/app/assets/stylesheets/alchemy/shoelace.scss +345 -0
- data/app/assets/stylesheets/alchemy/sitemap.scss +24 -14
- data/app/assets/stylesheets/alchemy/spinner.scss +9 -19
- data/app/assets/stylesheets/alchemy/tables.scss +16 -24
- data/app/assets/stylesheets/alchemy/tags.scss +4 -0
- data/app/assets/stylesheets/alchemy/toolbar.scss +29 -25
- data/app/assets/stylesheets/alchemy/upload.scss +140 -89
- data/app/assets/stylesheets/tinymce/skins/content/alchemy/content.min.scss +69 -0
- data/app/assets/stylesheets/tinymce/skins/skintool.json +38 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.css +711 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.css +705 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.min.css +7 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.min.css +7 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.css +29 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.min.css +7 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/fonts/tinymce-mobile.woff +0 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.min.scss +3798 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.css +677 -0
- data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.min.css +7 -0
- data/app/components/alchemy/admin/node_select.rb +39 -0
- data/app/components/alchemy/admin/page_select.rb +42 -0
- data/app/controllers/alchemy/admin/base_controller.rb +5 -6
- data/app/controllers/alchemy/admin/elements_controller.rb +63 -35
- data/app/controllers/alchemy/admin/pages_controller.rb +9 -4
- data/app/controllers/alchemy/base_controller.rb +4 -2
- data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +1 -1
- data/app/controllers/concerns/alchemy/site_redirects.rb +1 -1
- data/app/decorators/alchemy/element_editor.rb +0 -2
- data/app/helpers/alchemy/admin/attachments_helper.rb +6 -5
- data/app/helpers/alchemy/admin/base_helper.rb +17 -12
- data/app/helpers/alchemy/admin/ingredients_helper.rb +4 -1
- data/app/helpers/alchemy/admin/pages_helper.rb +5 -11
- data/app/helpers/alchemy/base_helper.rb +47 -13
- data/app/javascript/alchemy_admin/clipboard.js +16 -0
- data/app/javascript/alchemy_admin/components/alchemy_html_element.js +129 -0
- data/app/javascript/alchemy_admin/components/button.js +59 -0
- data/app/javascript/alchemy_admin/components/char_counter.js +40 -0
- data/app/javascript/alchemy_admin/components/datepicker.js +39 -0
- data/app/javascript/alchemy_admin/components/dialog_link.js +45 -0
- data/app/javascript/alchemy_admin/components/element_editor/publish_element_button.js +36 -0
- data/app/javascript/alchemy_admin/components/element_editor.js +553 -0
- data/app/javascript/alchemy_admin/components/ingredient_group.js +54 -0
- data/app/javascript/alchemy_admin/components/link_buttons/link_button.js +48 -0
- data/app/javascript/alchemy_admin/components/link_buttons/unlink_button.js +38 -0
- data/app/javascript/alchemy_admin/components/link_buttons.js +79 -0
- data/app/javascript/alchemy_admin/components/node_select.js +45 -0
- data/app/javascript/alchemy_admin/components/overlay.js +18 -0
- data/app/javascript/alchemy_admin/components/page_select.js +63 -0
- data/app/javascript/alchemy_admin/components/remote_select.js +134 -0
- data/app/javascript/alchemy_admin/components/select.js +12 -0
- data/app/javascript/alchemy_admin/components/spinner.js +31 -0
- data/app/javascript/alchemy_admin/components/tinymce.js +134 -0
- data/app/javascript/alchemy_admin/components/uploader/file_upload.js +266 -0
- data/app/javascript/alchemy_admin/components/uploader/progress.js +258 -0
- data/app/javascript/alchemy_admin/components/uploader.js +132 -0
- data/app/javascript/alchemy_admin/dirty.js +49 -0
- data/app/javascript/alchemy_admin/file_editors.js +1 -1
- data/app/javascript/alchemy_admin/gui.js +14 -0
- data/app/javascript/alchemy_admin/i18n.js +12 -8
- data/app/javascript/alchemy_admin/image_cropper.js +6 -3
- data/app/javascript/alchemy_admin/image_loader.js +7 -15
- data/app/javascript/alchemy_admin/ingredient_anchor_link.js +2 -5
- data/app/javascript/alchemy_admin/initializer.js +65 -0
- data/app/javascript/alchemy_admin/locales/en.js +31 -0
- data/app/javascript/alchemy_admin/picture_editors.js +6 -4
- data/app/javascript/alchemy_admin/picture_selector.js +38 -0
- data/app/javascript/alchemy_admin/please_wait_overlay.js +8 -0
- data/app/javascript/alchemy_admin/sortable_elements.js +78 -0
- data/app/javascript/alchemy_admin/spinner.js +36 -0
- data/app/javascript/alchemy_admin/tags_autocomplete.js +46 -0
- data/app/javascript/alchemy_admin/utils/ajax.js +6 -5
- data/app/javascript/alchemy_admin/utils/debounce.js +10 -0
- data/app/javascript/alchemy_admin/utils/dom_helpers.js +20 -0
- data/app/javascript/alchemy_admin/utils/format.js +11 -0
- data/app/javascript/alchemy_admin/utils/max.js +3 -0
- data/app/javascript/alchemy_admin/utils/string_conversions.js +10 -0
- data/app/javascript/alchemy_admin.js +64 -13
- data/app/javascript/menubar.js +10 -0
- data/app/models/alchemy/attachment.rb +9 -11
- data/app/models/alchemy/element.rb +11 -0
- data/app/models/alchemy/ingredients/richtext.rb +1 -10
- data/app/models/alchemy/node.rb +4 -0
- data/app/models/alchemy/page/page_naming.rb +7 -0
- data/app/models/alchemy/page/page_natures.rb +10 -2
- data/app/models/alchemy/page.rb +11 -51
- data/app/models/alchemy/picture/url.rb +1 -9
- data/app/models/alchemy/picture_variant.rb +11 -2
- data/app/models/concerns/alchemy/picture_thumbnails.rb +1 -1
- data/app/serializers/alchemy/page_tree_serializer.rb +2 -1
- data/app/services/alchemy/copy_page.rb +98 -0
- data/app/views/alchemy/_menubar.html.erb +17 -13
- data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +14 -10
- data/app/views/alchemy/admin/attachments/_attachment.html.erb +44 -36
- data/app/views/alchemy/admin/attachments/_replace_button.html.erb +15 -21
- data/app/views/alchemy/admin/attachments/archive_overlay.js.erb +0 -1
- data/app/views/alchemy/admin/attachments/assign.js.erb +1 -1
- data/app/views/alchemy/admin/attachments/index.html.erb +6 -4
- data/app/views/alchemy/admin/attachments/show.html.erb +10 -23
- data/app/views/alchemy/admin/clipboard/clear.js.erb +1 -1
- data/app/views/alchemy/admin/clipboard/index.html.erb +3 -7
- data/app/views/alchemy/admin/clipboard/insert.js.erb +1 -1
- data/app/views/alchemy/admin/crop.html.erb +1 -1
- data/app/views/alchemy/admin/dashboard/_locked_pages.html.erb +1 -1
- data/app/views/alchemy/admin/dashboard/index.html.erb +13 -11
- data/app/views/alchemy/admin/dashboard/info.html.erb +7 -7
- data/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb +21 -23
- data/app/views/alchemy/admin/elements/_element.html.erb +52 -44
- data/app/views/alchemy/admin/elements/_footer.html.erb +1 -1
- data/app/views/alchemy/admin/elements/_form.html.erb +1 -1
- data/app/views/alchemy/admin/elements/_header.html.erb +11 -12
- data/app/views/alchemy/admin/elements/_toolbar.html.erb +33 -45
- data/app/views/alchemy/admin/elements/create.js.erb +7 -15
- data/app/views/alchemy/admin/elements/destroy.js.erb +0 -2
- data/app/views/alchemy/admin/elements/index.html.erb +27 -24
- data/app/views/alchemy/admin/elements/new.html.erb +9 -11
- data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +2 -2
- data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +3 -3
- data/app/views/alchemy/admin/ingredients/_video_fields.html.erb +1 -2
- data/app/views/alchemy/admin/languages/_form.html.erb +2 -3
- data/app/views/alchemy/admin/languages/_language.html.erb +15 -8
- data/app/views/alchemy/admin/languages/_table.html.erb +1 -0
- data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +28 -16
- data/app/views/alchemy/admin/layoutpages/index.html.erb +2 -2
- data/app/views/alchemy/admin/legacy_page_urls/_legacy_page_url.html.erb +12 -8
- data/app/views/alchemy/admin/legacy_page_urls/_new.html.erb +1 -1
- data/app/views/alchemy/admin/nodes/_form.html.erb +20 -21
- data/app/views/alchemy/admin/nodes/_node.html.erb +39 -34
- data/app/views/alchemy/admin/nodes/index.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_anchor_link.html.erb +4 -4
- data/app/views/alchemy/admin/pages/_create_language_form.html.erb +2 -2
- data/app/views/alchemy/admin/pages/_current_page.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_external_link.html.erb +4 -4
- data/app/views/alchemy/admin/pages/_file_link.html.erb +5 -5
- data/app/views/alchemy/admin/pages/_form.html.erb +10 -21
- data/app/views/alchemy/admin/pages/_internal_link.html.erb +4 -4
- data/app/views/alchemy/admin/pages/_locked_page.html.erb +2 -2
- data/app/views/alchemy/admin/pages/_new_page_form.html.erb +4 -17
- data/app/views/alchemy/admin/pages/_page.html.erb +76 -72
- data/app/views/alchemy/admin/pages/_page_infos.html.erb +23 -7
- data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +2 -1
- data/app/views/alchemy/admin/pages/_page_status.html.erb +11 -21
- data/app/views/alchemy/admin/pages/_publication_fields.html.erb +2 -5
- data/app/views/alchemy/admin/pages/_table.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_table_row.html.erb +43 -39
- data/app/views/alchemy/admin/pages/_toolbar.html.erb +43 -38
- data/app/views/alchemy/admin/pages/configure.html.erb +12 -14
- data/app/views/alchemy/admin/pages/edit.html.erb +80 -103
- data/app/views/alchemy/admin/pages/info.html.erb +20 -11
- data/app/views/alchemy/admin/pages/link.html.erb +22 -16
- data/app/views/alchemy/admin/pages/new.html.erb +9 -11
- data/app/views/alchemy/admin/pages/unlock.js.erb +10 -3
- data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +15 -13
- data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +3 -5
- data/app/views/alchemy/admin/partials/_routes.html.erb +10 -2
- data/app/views/alchemy/admin/partials/_site_select.html.erb +6 -5
- data/app/views/alchemy/admin/partials/_toolbar_button.html.erb +28 -23
- data/app/views/alchemy/admin/pictures/_archive.html.erb +5 -5
- data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +21 -23
- data/app/views/alchemy/admin/pictures/_infos.html.erb +2 -6
- data/app/views/alchemy/admin/pictures/_picture.html.erb +17 -21
- data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +17 -16
- data/app/views/alchemy/admin/pictures/_tag_list.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/archive_overlay.js.erb +1 -1
- data/app/views/alchemy/admin/pictures/assign.js.erb +1 -1
- data/app/views/alchemy/admin/pictures/index.html.erb +34 -30
- data/app/views/alchemy/admin/pictures/show.html.erb +3 -3
- data/app/views/alchemy/admin/resources/_filter.html.erb +2 -2
- data/app/views/alchemy/admin/resources/_form.html.erb +2 -2
- data/app/views/alchemy/admin/resources/_per_page_select.html.erb +1 -1
- data/app/views/alchemy/admin/resources/_resource.html.erb +16 -9
- data/app/views/alchemy/admin/resources/_table.html.erb +4 -1
- data/app/views/alchemy/admin/resources/index.html.erb +22 -19
- data/app/views/alchemy/admin/sites/index.html.erb +2 -1
- data/app/views/alchemy/admin/styleguide/index.html.erb +54 -28
- data/app/views/alchemy/admin/tags/_tag.html.erb +16 -14
- data/app/views/alchemy/admin/tags/index.html.erb +15 -12
- data/app/views/alchemy/admin/tinymce/_setup.html.erb +28 -0
- data/app/views/alchemy/admin/uploader/_button.html.erb +23 -29
- data/app/views/alchemy/admin/uploader/_setup.html.erb +3 -8
- data/app/views/alchemy/base/500.html.erb +1 -1
- data/app/views/alchemy/base/error_notice.js.erb +0 -1
- data/app/views/alchemy/ingredients/_boolean_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/_datetime_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/_file_editor.html.erb +5 -5
- data/app/views/alchemy/ingredients/_link_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/_node_editor.html.erb +6 -19
- data/app/views/alchemy/ingredients/_page_editor.html.erb +7 -19
- data/app/views/alchemy/ingredients/_picture_editor.html.erb +2 -2
- data/app/views/alchemy/ingredients/_richtext_editor.html.erb +6 -15
- data/app/views/alchemy/ingredients/_select_editor.html.erb +2 -1
- data/app/views/alchemy/ingredients/_text_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/shared/_anchor.html.erb +1 -1
- data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +10 -20
- data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +42 -49
- data/app/views/kaminari/alchemy/_first_page.html.erb +4 -2
- data/app/views/kaminari/alchemy/_gap.html.erb +1 -1
- data/app/views/kaminari/alchemy/_last_page.html.erb +4 -2
- data/app/views/kaminari/alchemy/_next_page.html.erb +4 -2
- data/app/views/kaminari/alchemy/_prev_page.html.erb +4 -2
- data/app/views/layouts/alchemy/admin.html.erb +10 -29
- data/bundles/shoelace.js +10 -0
- data/bundles/tinymce.js +20 -0
- data/config/alchemy/config.yml +11 -10
- data/config/alchemy/modules.yml +30 -30
- data/config/brakeman.ignore +0 -34
- data/config/importmap.rb +9 -5
- data/config/initializers/dragonfly.rb +1 -0
- data/config/initializers/rails_live_reload.rb +13 -0
- data/config/locales/alchemy.en.yml +25 -9
- data/config/routes.rb +2 -1
- data/lib/alchemy/auth_accessors.rb +6 -1
- data/lib/alchemy/config.rb +24 -2
- data/lib/alchemy/dev_support/live_reload_watcher.rb +5 -0
- data/lib/alchemy/engine.rb +10 -3
- data/lib/alchemy/forms/builder.rb +18 -12
- data/lib/alchemy/resources_helper.rb +3 -3
- data/lib/alchemy/test_support/capybara_helpers.rb +8 -5
- data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +6 -6
- data/lib/alchemy/test_support/rspec_matchers.rb +14 -0
- data/lib/alchemy/test_support/shared_uploader_examples.rb +1 -1
- data/lib/alchemy/tinymce.rb +19 -3
- data/lib/alchemy/version.rb +1 -1
- data/package.json +30 -9
- data/rollup.config.mjs +65 -0
- data/vendor/assets/fonts/remixicon.eot +0 -0
- data/vendor/assets/fonts/remixicon.svg +7816 -0
- data/vendor/assets/fonts/remixicon.ttf +0 -0
- data/vendor/assets/fonts/remixicon.woff +0 -0
- data/vendor/assets/fonts/remixicon.woff2 +0 -0
- data/vendor/assets/stylesheets/remixicon.scss +10480 -0
- data/vendor/assets/stylesheets/tinymce/skins/content/default/content.min.css +1 -0
- data/vendor/javascript/clipboard.min.js +7 -0
- data/vendor/javascript/flatpickr.min.js +1 -0
- data/vendor/javascript/keymaster.min.js +1 -0
- data/vendor/javascript/rails-ujs.min.js +1 -0
- data/vendor/javascript/shoelace.min.js +995 -0
- data/vendor/javascript/sortable.min.js +7 -0
- data/vendor/javascript/tinymce.min.js +1 -0
- data/vendor/javascript/ungap-custom-elements.min.js +3 -0
- metadata +111 -124
- data/.codeclimate.yml +0 -35
- data/.editorconfig +0 -23
- data/.github/FUNDING.yml +0 -4
- data/.github/ISSUE_TEMPLATE/Bug_report.md +0 -22
- data/.github/ISSUE_TEMPLATE/Feature_request.md +0 -17
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -18
- data/.github/workflows/brakeman-analysis.yml +0 -46
- data/.github/workflows/lint.yml +0 -37
- data/.github/workflows/stale.yml +0 -33
- data/.github/workflows/test.yml +0 -124
- data/.gitignore +0 -31
- data/.hound.yml +0 -9
- data/.localeapp/config.rb +0 -8
- data/.prettierrc +0 -6
- data/.rspec +0 -1
- data/.rubocop.yml +0 -7
- data/.standard.yml +0 -4
- data/.yardopts +0 -5
- data/app/assets/javascripts/alchemy/alchemy.autocomplete.js.coffee +0 -30
- data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +0 -53
- data/app/assets/javascripts/alchemy/alchemy.buttons.js.coffee +0 -45
- data/app/assets/javascripts/alchemy/alchemy.char_counter.js.coffee +0 -19
- data/app/assets/javascripts/alchemy/alchemy.dirty.js.coffee +0 -59
- data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +0 -79
- data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +0 -267
- data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +0 -27
- data/app/assets/javascripts/alchemy/alchemy.spinner.js +0 -32
- data/app/assets/javascripts/alchemy/alchemy.tooltips.coffee +0 -10
- data/app/assets/javascripts/alchemy/alchemy.uploader.js.coffee +0 -131
- data/app/assets/javascripts/alchemy/menubar.js.coffee +0 -8
- data/app/assets/javascripts/alchemy/node_select.js +0 -39
- data/app/assets/javascripts/alchemy/page_select.js +0 -46
- data/app/assets/javascripts/alchemy/templates/node.hbs +0 -16
- data/app/assets/javascripts/alchemy/templates/spinner.hbs +0 -7
- data/app/assets/stylesheets/alchemy/jquery-ui.scss +0 -435
- data/app/assets/stylesheets/tinymce/skins/alchemy/content.min.css.scss +0 -94
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.svg +0 -63
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.ttf +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce-small.woff +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.svg +0 -129
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.ttf +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/fonts/tinymce.woff +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/img/anchor.gif +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/img/loader.gif +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/img/object.gif +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/img/trans.gif +0 -0
- data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +0 -2105
- data/app/javascript/alchemy_admin/datepicker.js +0 -33
- data/app/javascript/alchemy_admin/tinymce.js +0 -146
- data/app/javascript/alchemy_admin/translations.js +0 -32
- data/app/views/alchemy/admin/elements/fold.js.erb +0 -33
- data/app/views/alchemy/admin/elements/order.js.erb +0 -11
- data/app/views/alchemy/admin/elements/publish.js.erb +0 -21
- data/app/views/alchemy/admin/elements/update.js.erb +0 -27
- data/vendor/assets/fonts/fa-regular-400.eot +0 -0
- data/vendor/assets/fonts/fa-regular-400.svg +0 -803
- 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 +0 -4938
- 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/clipboard.min.js +0 -7
- data/vendor/assets/javascripts/fileupload/jquery.fileupload-process.js +0 -178
- data/vendor/assets/javascripts/fileupload/jquery.fileupload-validate.js +0 -125
- data/vendor/assets/javascripts/fileupload/jquery.fileupload.js +0 -1502
- data/vendor/assets/javascripts/fileupload/jquery.iframe-transport.js +0 -224
- data/vendor/assets/javascripts/jquery-ui/data.js +0 -45
- data/vendor/assets/javascripts/jquery-ui/ie.js +0 -20
- data/vendor/assets/javascripts/jquery-ui/keycode.js +0 -51
- data/vendor/assets/javascripts/jquery-ui/plugin.js +0 -49
- data/vendor/assets/javascripts/jquery-ui/safe-active-element.js +0 -46
- data/vendor/assets/javascripts/jquery-ui/safe-blur.js +0 -27
- data/vendor/assets/javascripts/jquery-ui/scroll-parent.js +0 -50
- data/vendor/assets/javascripts/jquery-ui/unique-id.js +0 -54
- data/vendor/assets/javascripts/jquery-ui/version.js +0 -20
- data/vendor/assets/javascripts/jquery-ui/widget.js +0 -754
- data/vendor/assets/javascripts/jquery-ui/widgets/draggable.js +0 -1268
- data/vendor/assets/javascripts/jquery-ui/widgets/mouse.js +0 -241
- data/vendor/assets/javascripts/jquery-ui/widgets/sortable.js +0 -1623
- data/vendor/assets/javascripts/jquery-ui/widgets/tabs.js +0 -931
- data/vendor/assets/javascripts/jquery_plugins/jquery.scrollTo.min.js +0 -7
- data/vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js +0 -296
- data/vendor/assets/javascripts/keymaster.js +0 -296
- data/vendor/assets/javascripts/requestAnimationFrame.js +0 -31
- data/vendor/assets/javascripts/tinymce/license.txt +0 -504
- data/vendor/assets/javascripts/tinymce/tinymce.min.js +0 -2
- data/vendor/assets/stylesheets/fontawesome/_animated.scss +0 -20
- data/vendor/assets/stylesheets/fontawesome/_bordered-pulled.scss +0 -20
- data/vendor/assets/stylesheets/fontawesome/_core.scss +0 -21
- data/vendor/assets/stylesheets/fontawesome/_fixed-width.scss +0 -6
- data/vendor/assets/stylesheets/fontawesome/_icons.scss +0 -1441
- data/vendor/assets/stylesheets/fontawesome/_larger.scss +0 -23
- data/vendor/assets/stylesheets/fontawesome/_list.scss +0 -18
- data/vendor/assets/stylesheets/fontawesome/_mixins.scss +0 -56
- data/vendor/assets/stylesheets/fontawesome/_rotated-flipped.scss +0 -24
- data/vendor/assets/stylesheets/fontawesome/_screen-reader.scss +0 -5
- data/vendor/assets/stylesheets/fontawesome/_stacked.scss +0 -31
- data/vendor/assets/stylesheets/fontawesome/_variables.scss +0 -1458
- data/vendor/assets/stylesheets/fontawesome/fontawesome.scss +0 -16
- data/vendor/assets/stylesheets/fontawesome/regular.scss +0 -23
- data/vendor/assets/stylesheets/fontawesome/solid.scss +0 -24
@@ -0,0 +1,14 @@
|
|
1
|
+
import TagsAutocomplete from "alchemy_admin/tags_autocomplete"
|
2
|
+
|
3
|
+
function init(scope) {
|
4
|
+
if (!scope) {
|
5
|
+
Alchemy.watchForDialogs()
|
6
|
+
}
|
7
|
+
Alchemy.Hotkeys(scope)
|
8
|
+
Alchemy.ListFilter(scope)
|
9
|
+
TagsAutocomplete(scope)
|
10
|
+
}
|
11
|
+
|
12
|
+
export default {
|
13
|
+
init
|
14
|
+
}
|
@@ -1,11 +1,8 @@
|
|
1
|
-
|
1
|
+
import { en } from "alchemy_admin/locales/en"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
}
|
7
|
-
return Alchemy.locale
|
8
|
-
}
|
3
|
+
Alchemy.translations = Object.assign(Alchemy.translations || {}, { en })
|
4
|
+
|
5
|
+
const KEY_SEPARATOR = /\./
|
9
6
|
|
10
7
|
function getTranslations() {
|
11
8
|
const locale = currentLocale()
|
@@ -36,7 +33,14 @@ function getTranslation(key) {
|
|
36
33
|
return translations[key] || key
|
37
34
|
}
|
38
35
|
|
39
|
-
export
|
36
|
+
export function currentLocale() {
|
37
|
+
if (document.documentElement.lang) {
|
38
|
+
return document.documentElement.lang
|
39
|
+
}
|
40
|
+
return "en"
|
41
|
+
}
|
42
|
+
|
43
|
+
export function translate(key, replacement = undefined) {
|
40
44
|
let translation = getTranslation(key)
|
41
45
|
|
42
46
|
if (replacement) {
|
@@ -90,12 +90,15 @@ export default class ImageCropper {
|
|
90
90
|
}
|
91
91
|
|
92
92
|
bind() {
|
93
|
-
this.dialog.dialog_body.find('button[type="submit"]').click(
|
94
|
-
|
93
|
+
this.dialog.dialog_body.find('button[type="submit"]').on("click", () => {
|
94
|
+
const elementEditor = document.querySelector(
|
95
|
+
`[data-element-id='${this.elementId}']`
|
96
|
+
)
|
97
|
+
elementEditor.setDirty()
|
95
98
|
this.dialog.close()
|
96
99
|
return false
|
97
100
|
})
|
98
|
-
this.dialog.dialog_body.find('button[type="reset"]').click(
|
101
|
+
this.dialog.dialog_body.find('button[type="reset"]').on("click", () => {
|
99
102
|
this.reset()
|
100
103
|
return false
|
101
104
|
})
|
@@ -1,23 +1,21 @@
|
|
1
1
|
// Shows spinner while loading images and
|
2
2
|
// fades the image after its been loaded
|
3
3
|
|
4
|
-
const DEFAULT_SPINNER_OPTIONS = { fill: "#fff" }
|
5
|
-
|
6
4
|
export default class ImageLoader {
|
7
|
-
static init(scope = document
|
5
|
+
static init(scope = document) {
|
8
6
|
if (typeof scope === "string") {
|
9
7
|
scope = document.querySelector(scope)
|
10
8
|
}
|
11
9
|
scope.querySelectorAll("img").forEach((image) => {
|
12
|
-
const loader = new ImageLoader(image
|
10
|
+
const loader = new ImageLoader(image)
|
13
11
|
loader.load()
|
14
12
|
})
|
15
13
|
}
|
16
14
|
|
17
|
-
constructor(image
|
15
|
+
constructor(image) {
|
18
16
|
this.image = image
|
19
17
|
this.parent = image.parentNode
|
20
|
-
this.spinner = new Alchemy.Spinner("small"
|
18
|
+
this.spinner = new Alchemy.Spinner("small")
|
21
19
|
this.bind()
|
22
20
|
}
|
23
21
|
|
@@ -34,15 +32,15 @@ export default class ImageLoader {
|
|
34
32
|
}
|
35
33
|
|
36
34
|
onLoaded() {
|
37
|
-
this.
|
35
|
+
this.spinner.stop()
|
38
36
|
this.image.classList.remove("loading")
|
39
37
|
this.unbind()
|
40
38
|
}
|
41
39
|
|
42
40
|
onError(evt) {
|
43
41
|
const message = `Could not load "${this.image.src}"`
|
44
|
-
this.
|
45
|
-
this.parent.innerHTML = `<span class="icon error
|
42
|
+
this.spinner.stop()
|
43
|
+
this.parent.innerHTML = `<span class="icon error ri-alert-line" title="${message}" />`
|
46
44
|
console.error(message, evt)
|
47
45
|
this.unbind()
|
48
46
|
}
|
@@ -51,10 +49,4 @@ export default class ImageLoader {
|
|
51
49
|
this.image.removeEventListener("load", this.onLoaded)
|
52
50
|
this.image.removeEventListener("error", this.onError)
|
53
51
|
}
|
54
|
-
|
55
|
-
removeSpinner() {
|
56
|
-
this.parent.querySelectorAll(".spinner").forEach((spinner) => {
|
57
|
-
spinner.remove()
|
58
|
-
})
|
59
|
-
}
|
60
52
|
}
|
@@ -7,11 +7,8 @@ export default class IngredientAnchorLink {
|
|
7
7
|
const icon = ingredientEditor.querySelector(
|
8
8
|
".edit-ingredient-anchor-link > a > .icon"
|
9
9
|
)
|
10
|
-
|
11
|
-
|
12
|
-
? icon.classList.replace("far", "fas")
|
13
|
-
: icon.classList.replace("fas", "far")
|
14
|
-
}
|
10
|
+
icon?.classList.toggle("ri-bookmark-fill", active)
|
11
|
+
icon?.classList.toggle("ri-bookmark-line", !active)
|
15
12
|
}
|
16
13
|
}
|
17
14
|
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
/**
|
2
|
+
* add change listener to select to redirect the user after selecting another locale or site
|
3
|
+
* @param {string} selectId
|
4
|
+
* @param {string} parameterName
|
5
|
+
* @param {boolean} forcedReload
|
6
|
+
*/
|
7
|
+
function selectHandler(selectId, parameterName, forcedReload = false) {
|
8
|
+
$(`select#${selectId}`).on("change", function (e) {
|
9
|
+
let url = window.location.pathname
|
10
|
+
let delimiter = url.match(/\?/) ? "&" : "?"
|
11
|
+
const location = `${url}${delimiter}${parameterName}=${$(this).val()}`
|
12
|
+
|
13
|
+
if (forcedReload) {
|
14
|
+
window.location.href = location
|
15
|
+
} else {
|
16
|
+
Turbo.visit(location, {})
|
17
|
+
}
|
18
|
+
})
|
19
|
+
}
|
20
|
+
|
21
|
+
function Initialize() {
|
22
|
+
// We obviously have javascript enabled.
|
23
|
+
$("html").removeClass("no-js")
|
24
|
+
|
25
|
+
// Initialize the GUI.
|
26
|
+
Alchemy.GUI.init()
|
27
|
+
|
28
|
+
// Fade all growl notifications.
|
29
|
+
if ($("#flash_notices").length > 0) {
|
30
|
+
Alchemy.Growler.fade()
|
31
|
+
}
|
32
|
+
|
33
|
+
// Add observer for please wait overlay.
|
34
|
+
$(".please_wait")
|
35
|
+
.not("*[data-alchemy-confirm]")
|
36
|
+
.on("click", Alchemy.pleaseWaitOverlay)
|
37
|
+
|
38
|
+
// Hack for enabling tab focus for <a>'s styled as button.
|
39
|
+
$("a.button").attr({ tabindex: 0 })
|
40
|
+
|
41
|
+
// Locale select handler
|
42
|
+
selectHandler("change_locale", "admin_locale", true)
|
43
|
+
|
44
|
+
// Site select handler
|
45
|
+
selectHandler("change_site", "site_id")
|
46
|
+
|
47
|
+
// Submit forms of selects with `data-autosubmit="true"`
|
48
|
+
$('select[data-auto-submit="true"]').on("change", function () {
|
49
|
+
$(this.form).submit()
|
50
|
+
})
|
51
|
+
|
52
|
+
// Attaches the image loader on all images
|
53
|
+
Alchemy.ImageLoader("#main_content")
|
54
|
+
|
55
|
+
// Override the filter of keymaster.js so we can blur the fields on esc key.
|
56
|
+
key.filter = function (event) {
|
57
|
+
let tagName = (event.target || event.srcElement).tagName
|
58
|
+
return (
|
59
|
+
key.isPressed("esc") ||
|
60
|
+
!(tagName === "INPUT" || tagName === "SELECT" || tagName === "TEXTAREA")
|
61
|
+
)
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
export default Initialize
|
@@ -0,0 +1,31 @@
|
|
1
|
+
export const en = {
|
2
|
+
allowed_chars: "of %{count} chars",
|
3
|
+
cancel: "Cancel",
|
4
|
+
cancelled: "Cancelled",
|
5
|
+
click_to_edit: "click to edit",
|
6
|
+
complete: "Complete",
|
7
|
+
element_dirty_notice:
|
8
|
+
"This element has unsaved changes. Do you really want to fold it?",
|
9
|
+
help: "Help",
|
10
|
+
ok: "Ok",
|
11
|
+
page_dirty_notice:
|
12
|
+
"You have unsaved changes on this page. They will be lost if you continue.",
|
13
|
+
page_found: "Page found",
|
14
|
+
pages_found: "Pages found",
|
15
|
+
url_validation_failed: "The url has no valid format.",
|
16
|
+
warning: "Warning!",
|
17
|
+
"File is too large": "File is too large",
|
18
|
+
"File is too small": "File is too small",
|
19
|
+
"File type not allowed": "File type not allowed",
|
20
|
+
"Maximum number of files exceeded": "Maximum number of files exceeded",
|
21
|
+
"Uploaded bytes exceed file size": "Uploaded bytes exceed file size",
|
22
|
+
"Abort upload": "Abort upload",
|
23
|
+
"Cancel all uploads": "Cancel all uploads",
|
24
|
+
Close: "Close",
|
25
|
+
formats: {
|
26
|
+
datetime: "Y-m-d H:i",
|
27
|
+
date: "Y-m-d",
|
28
|
+
time: "H:i",
|
29
|
+
time_24hr: false
|
30
|
+
}
|
31
|
+
}
|
@@ -1,10 +1,10 @@
|
|
1
|
-
import debounce from "
|
2
|
-
import max from "
|
1
|
+
import debounce from "alchemy_admin/utils/debounce"
|
2
|
+
import max from "alchemy_admin/utils/max"
|
3
3
|
import { get } from "alchemy_admin/utils/ajax"
|
4
4
|
import ImageLoader from "alchemy_admin/image_loader"
|
5
5
|
|
6
6
|
const UPDATE_DELAY = 125
|
7
|
-
const IMAGE_PLACEHOLDER = '<i class="icon
|
7
|
+
const IMAGE_PLACEHOLDER = '<i class="icon ri-image-line ri-fw"></i>'
|
8
8
|
const THUMBNAIL_SIZE = "160x120"
|
9
9
|
|
10
10
|
class PictureEditor {
|
@@ -27,6 +27,8 @@ class PictureEditor {
|
|
27
27
|
this.imageLoader = new ImageLoader(this.image)
|
28
28
|
}
|
29
29
|
|
30
|
+
// The mutation observer is observing multiple fields that all get updated
|
31
|
+
// simultaneously. We only want to update the image once, so we debounce.
|
30
32
|
this.update = debounce(() => {
|
31
33
|
this.updateImage()
|
32
34
|
this.updateCropLink()
|
@@ -93,7 +95,7 @@ class PictureEditor {
|
|
93
95
|
this.pictureIdField.value = ""
|
94
96
|
this.image = null
|
95
97
|
this.cropLink.classList.add("disabled")
|
96
|
-
|
98
|
+
this.container.closest(".element-editor").setDirty()
|
97
99
|
}
|
98
100
|
|
99
101
|
updateCropLink() {
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { on } from "alchemy_admin/utils/events"
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Multiple picture select handler for the picture archive.
|
5
|
+
*/
|
6
|
+
export default function PictureSelector() {
|
7
|
+
const selectedItemTools = document.querySelector(".selected_item_tools")
|
8
|
+
const checkedInputs = () =>
|
9
|
+
document.querySelectorAll("#picture_archive input:checked")
|
10
|
+
|
11
|
+
// make the item toolbar visible and show the checkbox also if it is not hovered anymore
|
12
|
+
on("change", ".picture_tool.select", "input", (event) => {
|
13
|
+
selectedItemTools.style.display =
|
14
|
+
checkedInputs().length > 0 ? "block" : "none"
|
15
|
+
|
16
|
+
const parentElementClassList = event.target.parentElement.classList
|
17
|
+
const checked = event.target.checked
|
18
|
+
|
19
|
+
parentElementClassList.toggle("visible", checked)
|
20
|
+
parentElementClassList.toggle("hidden", !checked)
|
21
|
+
})
|
22
|
+
|
23
|
+
// open the edit view in a dialog modal
|
24
|
+
on("click", ".selected_item_tools", "a#edit_multiple_pictures", (event) => {
|
25
|
+
event.preventDefault()
|
26
|
+
|
27
|
+
const searchParameters = new URLSearchParams()
|
28
|
+
checkedInputs().forEach((entry) =>
|
29
|
+
searchParameters.append(entry.name, entry.value)
|
30
|
+
)
|
31
|
+
const url = event.target.href + "?" + searchParameters.toString()
|
32
|
+
|
33
|
+
Alchemy.openDialog(url, {
|
34
|
+
title: event.target.title,
|
35
|
+
size: "400x295"
|
36
|
+
})
|
37
|
+
})
|
38
|
+
}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import Sortable from "sortablejs"
|
2
|
+
import { post } from "alchemy_admin/utils/ajax"
|
3
|
+
|
4
|
+
const SORTABLE_OPTIONS = {
|
5
|
+
draggable: ".element-editor",
|
6
|
+
handle: ".element-handle",
|
7
|
+
ghostClass: "dragged",
|
8
|
+
animation: 150,
|
9
|
+
swapThreshold: 0.65,
|
10
|
+
easing: "cubic-bezier(1, 0, 0, 1)"
|
11
|
+
}
|
12
|
+
|
13
|
+
function onStart(event) {
|
14
|
+
const name = event.item.dataset.elementName
|
15
|
+
document
|
16
|
+
.querySelectorAll(`[data-droppable-elements~="${name}"]`)
|
17
|
+
.forEach((dropzone) => dropzone.classList.add("droppable-elements"))
|
18
|
+
}
|
19
|
+
|
20
|
+
function onSort(event) {
|
21
|
+
const item = event.item
|
22
|
+
const parentElement = event.to.parentElement.closest(".element-editor")
|
23
|
+
const params = {
|
24
|
+
element_id: item.dataset.elementId,
|
25
|
+
position: event.newIndex + 1
|
26
|
+
}
|
27
|
+
|
28
|
+
if (parentElement) {
|
29
|
+
params.parent_element_id = parentElement.dataset.elementId
|
30
|
+
}
|
31
|
+
|
32
|
+
post(Alchemy.routes.order_admin_elements_path, params).then((response) => {
|
33
|
+
const data = response.data
|
34
|
+
Alchemy.growl(data.message)
|
35
|
+
Alchemy.PreviewWindow.refresh()
|
36
|
+
item.updateTitle(data.preview_text)
|
37
|
+
})
|
38
|
+
}
|
39
|
+
|
40
|
+
function onEnd() {
|
41
|
+
const dropzones = document.querySelectorAll("[data-droppable-elements]")
|
42
|
+
dropzones.forEach((dropzone) =>
|
43
|
+
dropzone.classList.remove("droppable-elements")
|
44
|
+
)
|
45
|
+
}
|
46
|
+
|
47
|
+
function createSortable(element, options = {}) {
|
48
|
+
const group = {
|
49
|
+
name: element.dataset.elementName,
|
50
|
+
put(to, _from, item) {
|
51
|
+
return to.el.dataset.droppableElements
|
52
|
+
.split(" ")
|
53
|
+
.includes(item.dataset.elementName)
|
54
|
+
}
|
55
|
+
}
|
56
|
+
new Sortable(element, {
|
57
|
+
...SORTABLE_OPTIONS,
|
58
|
+
...options,
|
59
|
+
onStart,
|
60
|
+
onSort,
|
61
|
+
onEnd,
|
62
|
+
group
|
63
|
+
})
|
64
|
+
}
|
65
|
+
|
66
|
+
export default function SortableElements(selector) {
|
67
|
+
if (selector == null) selector = ".sortable-elements"
|
68
|
+
|
69
|
+
const sortable_areas = document.querySelectorAll(selector, {
|
70
|
+
direction: "vertical"
|
71
|
+
})
|
72
|
+
|
73
|
+
sortable_areas.forEach((element) => createSortable(element))
|
74
|
+
|
75
|
+
document.querySelectorAll(".nested-elements").forEach((nestedElement) => {
|
76
|
+
createSortable(nestedElement)
|
77
|
+
})
|
78
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { createHtmlElement } from "alchemy_admin/utils/dom_helpers"
|
2
|
+
|
3
|
+
export default class Spinner {
|
4
|
+
constructor(size, color = "currentColor") {
|
5
|
+
this.size = size
|
6
|
+
this.color = color
|
7
|
+
this.spinner = undefined
|
8
|
+
}
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @returns {HTMLElement|undefined}
|
12
|
+
*/
|
13
|
+
get el() {
|
14
|
+
return this.spinner
|
15
|
+
}
|
16
|
+
/**
|
17
|
+
* @param {HTMLElement|undefined} parent
|
18
|
+
*/
|
19
|
+
spin(parent) {
|
20
|
+
if (typeof parent === "undefined") {
|
21
|
+
parent = document.body
|
22
|
+
}
|
23
|
+
this.spinner = createHtmlElement(
|
24
|
+
`<alchemy-spinner size="${this.size}" color="${this.color}"></alchemy-spinner>`
|
25
|
+
)
|
26
|
+
parent.append(this.spinner)
|
27
|
+
return this
|
28
|
+
}
|
29
|
+
|
30
|
+
stop() {
|
31
|
+
if (this.spinner) {
|
32
|
+
this.spinner.remove()
|
33
|
+
this.spinner = undefined
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
function createSearchChoice(term, data) {
|
2
|
+
if (
|
3
|
+
$(data).filter(function () {
|
4
|
+
return this.text.localeCompare(term) === 0
|
5
|
+
}).length === 0
|
6
|
+
) {
|
7
|
+
return {
|
8
|
+
id: term,
|
9
|
+
text: term
|
10
|
+
}
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
function initSelection(element, callback) {
|
15
|
+
const data = []
|
16
|
+
$(element.val().split(",")).each(function () {
|
17
|
+
data.push({
|
18
|
+
id: this.trim(),
|
19
|
+
text: this
|
20
|
+
})
|
21
|
+
})
|
22
|
+
callback(data)
|
23
|
+
}
|
24
|
+
|
25
|
+
export default function TagsAutocomplete(scope) {
|
26
|
+
const field = $("[data-autocomplete]", scope)
|
27
|
+
const url = field.data("autocomplete")
|
28
|
+
field.select2({
|
29
|
+
tags: true,
|
30
|
+
tokenSeparators: [","],
|
31
|
+
minimumInputLength: 1,
|
32
|
+
openOnEnter: false,
|
33
|
+
createSearchChoice,
|
34
|
+
ajax: {
|
35
|
+
url,
|
36
|
+
dataType: "json",
|
37
|
+
data: (term) => {
|
38
|
+
return { term }
|
39
|
+
},
|
40
|
+
results: (data) => {
|
41
|
+
return { results: data }
|
42
|
+
}
|
43
|
+
},
|
44
|
+
initSelection
|
45
|
+
})
|
46
|
+
}
|
@@ -24,7 +24,7 @@ function buildPromise(xhr) {
|
|
24
24
|
})
|
25
25
|
}
|
26
26
|
|
27
|
-
function getToken() {
|
27
|
+
export function getToken() {
|
28
28
|
const metaTag = document.querySelector('meta[name="csrf-token"]')
|
29
29
|
return metaTag.attributes.content.textContent
|
30
30
|
}
|
@@ -37,11 +37,11 @@ export function patch(url, data) {
|
|
37
37
|
return ajax("PATCH", url, data)
|
38
38
|
}
|
39
39
|
|
40
|
-
export function post(url, data) {
|
41
|
-
return ajax("POST", url, data)
|
40
|
+
export function post(url, data, accept = "application/json") {
|
41
|
+
return ajax("POST", url, data, accept)
|
42
42
|
}
|
43
43
|
|
44
|
-
export default function ajax(method, path, data) {
|
44
|
+
export default function ajax(method, path, data, accept = "application/json") {
|
45
45
|
const xhr = new XMLHttpRequest()
|
46
46
|
const promise = buildPromise(xhr)
|
47
47
|
const url = new URL(window.location.origin + path)
|
@@ -52,7 +52,8 @@ export default function ajax(method, path, data) {
|
|
52
52
|
|
53
53
|
xhr.open(method, url.toString())
|
54
54
|
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8")
|
55
|
-
xhr.setRequestHeader("Accept",
|
55
|
+
xhr.setRequestHeader("Accept", accept)
|
56
|
+
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
|
56
57
|
xhr.setRequestHeader("X-CSRF-Token", getToken())
|
57
58
|
|
58
59
|
if (data && method.toLowerCase() !== "get") {
|
@@ -0,0 +1,20 @@
|
|
1
|
+
/**
|
2
|
+
* create a HTML element
|
3
|
+
* @param {string} text
|
4
|
+
* @returns {HTMLElement}
|
5
|
+
*/
|
6
|
+
export function createHtmlElement(text) {
|
7
|
+
const element = document.createElement("template")
|
8
|
+
element.innerHTML = text
|
9
|
+
return element.content.children[0]
|
10
|
+
}
|
11
|
+
|
12
|
+
/**
|
13
|
+
* wrap element with wrappingElement
|
14
|
+
* @param {HTMLElement} element
|
15
|
+
* @param {HTMLElement} wrappingElement
|
16
|
+
*/
|
17
|
+
export function wrap(element, wrappingElement) {
|
18
|
+
element.replaceWith(wrappingElement)
|
19
|
+
wrappingElement.appendChild(element)
|
20
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
export function formatFileSize(bytes) {
|
2
|
+
let exponent = bytes === 0 ? 0 : Math.floor(Math.log(bytes) / Math.log(1024))
|
3
|
+
|
4
|
+
// prevent format higher than GB
|
5
|
+
if (exponent > 3) {
|
6
|
+
exponent = 3
|
7
|
+
}
|
8
|
+
|
9
|
+
let value = (bytes / Math.pow(1024, exponent)).toFixed(2)
|
10
|
+
return value + " " + ["B", "kB", "MB", "GB"][exponent]
|
11
|
+
}
|
@@ -1,17 +1,63 @@
|
|
1
|
+
import "@ungap/custom-elements"
|
1
2
|
import "@hotwired/turbo-rails"
|
3
|
+
import "keymaster"
|
2
4
|
|
3
|
-
import
|
4
|
-
|
5
|
-
import
|
5
|
+
import Rails from "@rails/ujs"
|
6
|
+
|
7
|
+
import GUI from "alchemy_admin/gui"
|
8
|
+
import { translate } from "alchemy_admin/i18n"
|
9
|
+
import Dirty from "alchemy_admin/dirty"
|
6
10
|
import IngredientAnchorLink from "alchemy_admin/ingredient_anchor_link"
|
7
|
-
import pictureEditors from "alchemy_admin/picture_editors"
|
8
11
|
import ImageLoader from "alchemy_admin/image_loader"
|
9
12
|
import ImageCropper from "alchemy_admin/image_cropper"
|
10
|
-
import
|
13
|
+
import Initializer from "alchemy_admin/initializer"
|
14
|
+
import pictureSelector from "alchemy_admin/picture_selector"
|
15
|
+
import pleaseWaitOverlay from "alchemy_admin/please_wait_overlay"
|
11
16
|
import Sitemap from "alchemy_admin/sitemap"
|
12
|
-
import
|
17
|
+
import SortableElements from "alchemy_admin/sortable_elements"
|
18
|
+
import Spinner from "alchemy_admin/spinner"
|
13
19
|
import PagePublicationFields from "alchemy_admin/page_publication_fields"
|
14
20
|
|
21
|
+
// Web Components
|
22
|
+
import "alchemy_admin/components/button"
|
23
|
+
import "alchemy_admin/components/char_counter"
|
24
|
+
import "alchemy_admin/components/datepicker"
|
25
|
+
import "alchemy_admin/components/dialog_link"
|
26
|
+
import "alchemy_admin/components/element_editor"
|
27
|
+
import "alchemy_admin/components/ingredient_group"
|
28
|
+
import "alchemy_admin/components/link_buttons"
|
29
|
+
import "alchemy_admin/components/node_select"
|
30
|
+
import "alchemy_admin/components/uploader"
|
31
|
+
import "alchemy_admin/components/overlay"
|
32
|
+
import "alchemy_admin/components/page_select"
|
33
|
+
import "alchemy_admin/components/select"
|
34
|
+
import "alchemy_admin/components/spinner"
|
35
|
+
import "alchemy_admin/components/tinymce"
|
36
|
+
import "alchemy_admin/clipboard"
|
37
|
+
|
38
|
+
import { setDefaultAnimation } from "shoelace"
|
39
|
+
|
40
|
+
// Change the default animation for all dialogs
|
41
|
+
setDefaultAnimation("tooltip.show", {
|
42
|
+
keyframes: [
|
43
|
+
{ transform: "translateY(10px)", opacity: "0" },
|
44
|
+
{ transform: "translateY(0)", opacity: "1" }
|
45
|
+
],
|
46
|
+
options: {
|
47
|
+
duration: 100
|
48
|
+
}
|
49
|
+
})
|
50
|
+
|
51
|
+
setDefaultAnimation("tooltip.hide", {
|
52
|
+
keyframes: [
|
53
|
+
{ transform: "translateY(0)", opacity: "1" },
|
54
|
+
{ transform: "translateY(10px)", opacity: "0" }
|
55
|
+
],
|
56
|
+
options: {
|
57
|
+
duration: 100
|
58
|
+
}
|
59
|
+
})
|
60
|
+
|
15
61
|
// Global Alchemy object
|
16
62
|
if (typeof window.Alchemy === "undefined") {
|
17
63
|
window.Alchemy = {}
|
@@ -19,16 +65,21 @@ if (typeof window.Alchemy === "undefined") {
|
|
19
65
|
|
20
66
|
// Enhance the global Alchemy object with imported features
|
21
67
|
Object.assign(Alchemy, {
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
fileEditors,
|
26
|
-
pictureEditors,
|
68
|
+
...Dirty,
|
69
|
+
GUI,
|
70
|
+
t: translate, // Global utility method for translating a given string
|
27
71
|
ImageLoader: ImageLoader.init,
|
28
72
|
ImageCropper,
|
73
|
+
Initializer,
|
29
74
|
IngredientAnchorLink,
|
30
|
-
|
75
|
+
pictureSelector,
|
76
|
+
pleaseWaitOverlay,
|
31
77
|
Sitemap,
|
32
|
-
|
78
|
+
SortableElements,
|
79
|
+
Spinner,
|
33
80
|
PagePublicationFields
|
34
81
|
})
|
82
|
+
|
83
|
+
Rails.start()
|
84
|
+
|
85
|
+
$(document).on("turbo:load", Initializer)
|