alchemy_cms 7.1.11 → 7.2.0.b
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +132 -24
- data/Gemfile +2 -4
- data/LICENSE +1 -1
- data/README.md +5 -6
- data/SECURITY.md +1 -1
- data/alchemy_cms.gemspec +3 -4
- data/app/assets/javascripts/alchemy/admin.js +0 -9
- data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +5 -15
- data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +5 -4
- data/app/assets/javascripts/alchemy/templates/index.js +0 -1
- data/app/assets/javascripts/alchemy/templates/node_folder.hbs +1 -1
- data/app/assets/javascripts/alchemy/templates/page_folder.hbs +1 -1
- data/app/assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js +20 -7
- data/app/assets/stylesheets/alchemy/_custom-properties.scss +12 -0
- data/app/assets/stylesheets/alchemy/_mixins.scss +10 -6
- data/app/assets/stylesheets/alchemy/_variables.scss +3 -0
- data/app/assets/stylesheets/alchemy/admin.scss +2 -2
- data/app/assets/stylesheets/alchemy/archive.scss +4 -3
- data/app/assets/stylesheets/alchemy/attachment-select.scss +19 -0
- data/app/assets/stylesheets/alchemy/base.scss +31 -18
- data/app/assets/stylesheets/alchemy/buttons.scss +3 -4
- data/app/assets/stylesheets/alchemy/dashboard.scss +1 -1
- data/app/assets/stylesheets/alchemy/dialogs.scss +2 -5
- data/app/assets/stylesheets/alchemy/elements.scss +73 -41
- data/app/assets/stylesheets/alchemy/flash.scss +20 -70
- data/app/assets/stylesheets/alchemy/forms.scss +41 -36
- data/app/assets/stylesheets/alchemy/frame.scss +12 -3
- data/app/assets/stylesheets/alchemy/icons.scss +34 -2
- data/app/assets/stylesheets/alchemy/image_library.scss +18 -9
- data/app/assets/stylesheets/alchemy/{filter_field.scss → list_filter.scss} +8 -7
- data/app/assets/stylesheets/alchemy/lists.scss +1 -1
- data/app/assets/stylesheets/alchemy/navigation.scss +9 -12
- data/app/assets/stylesheets/alchemy/node-select.scss +1 -1
- data/app/assets/stylesheets/alchemy/nodes.scss +15 -13
- data/app/assets/stylesheets/alchemy/notices.scss +56 -39
- data/app/assets/stylesheets/alchemy/page-select.scss +1 -4
- data/app/assets/stylesheets/alchemy/pagination.scss +11 -1
- data/app/assets/stylesheets/alchemy/preview_window.scss +3 -3
- data/app/assets/stylesheets/alchemy/search.scss +4 -4
- data/app/assets/stylesheets/alchemy/selects.scss +13 -7
- data/app/assets/stylesheets/alchemy/shoelace.scss +33 -2
- data/app/assets/stylesheets/alchemy/sitemap.scss +155 -159
- data/app/assets/stylesheets/alchemy/tables.scss +49 -12
- data/app/assets/stylesheets/alchemy/tags.scss +17 -11
- data/app/assets/stylesheets/alchemy/toolbar.scss +2 -2
- data/app/assets/stylesheets/alchemy/typography.scss +41 -22
- data/app/assets/stylesheets/alchemy/upload.scss +5 -4
- data/app/components/alchemy/admin/attachment_select.rb +39 -0
- data/app/components/alchemy/admin/icon.rb +72 -0
- data/app/components/alchemy/admin/link_dialog/anchor_tab.rb +41 -0
- data/app/components/alchemy/admin/link_dialog/base_tab.rb +75 -0
- data/app/components/alchemy/admin/link_dialog/external_tab.rb +42 -0
- data/app/components/alchemy/admin/link_dialog/file_tab.rb +45 -0
- data/app/components/alchemy/admin/link_dialog/internal_tab.rb +66 -0
- data/app/components/alchemy/admin/link_dialog/tabs.rb +33 -0
- data/app/components/alchemy/admin/list_filter.rb +42 -0
- data/app/components/alchemy/admin/message.rb +19 -0
- data/app/components/alchemy/admin/tags_autocomplete.rb +25 -0
- data/app/components/alchemy/admin/toolbar_button.rb +111 -0
- data/app/components/alchemy/ingredients/link_view.rb +1 -7
- data/app/components/alchemy/ingredients/picture_view.rb +2 -2
- data/app/components/alchemy/ingredients/text_view.rb +1 -2
- data/app/controllers/alchemy/admin/base_controller.rb +1 -1
- data/app/controllers/alchemy/admin/elements_controller.rb +4 -2
- data/app/controllers/alchemy/admin/ingredients_controller.rb +2 -0
- data/app/controllers/alchemy/admin/languages_controller.rb +1 -1
- data/app/controllers/alchemy/admin/layoutpages_controller.rb +0 -19
- data/app/controllers/alchemy/admin/legacy_page_urls_controller.rb +12 -4
- data/app/controllers/alchemy/admin/nodes_controller.rb +26 -0
- data/app/controllers/alchemy/admin/pages_controller.rb +11 -78
- data/app/controllers/alchemy/admin/picture_descriptions_controller.rb +15 -0
- data/app/controllers/alchemy/admin/pictures_controller.rb +18 -1
- data/app/controllers/alchemy/admin/resources_controller.rb +15 -10
- data/app/controllers/alchemy/api/attachments_controller.rb +44 -0
- data/app/controllers/alchemy/api/pages_controller.rb +10 -6
- data/app/controllers/alchemy/base_controller.rb +2 -2
- data/app/controllers/alchemy/messages_controller.rb +3 -3
- data/app/controllers/alchemy/pages_controller.rb +8 -6
- data/app/controllers/concerns/alchemy/admin/current_language.rb +1 -11
- data/app/controllers/concerns/alchemy/legacy_page_redirects.rb +1 -1
- data/app/decorators/alchemy/element_editor.rb +2 -2
- data/app/helpers/alchemy/admin/base_helper.rb +8 -60
- data/app/helpers/alchemy/admin/elements_helper.rb +1 -1
- data/app/helpers/alchemy/admin/ingredients_helper.rb +1 -1
- data/app/helpers/alchemy/base_helper.rb +9 -91
- data/app/helpers/alchemy/elements_helper.rb +3 -3
- data/app/helpers/alchemy/pages_helper.rb +16 -9
- data/app/javascript/alchemy_admin/components/attachment_select.js +24 -0
- data/app/javascript/alchemy_admin/components/button.js +3 -0
- data/app/javascript/alchemy_admin/components/clipboard_button.js +3 -2
- data/app/javascript/alchemy_admin/components/dialog_link.js +10 -7
- data/app/javascript/alchemy_admin/components/dom_id_select.js +69 -0
- data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +42 -0
- data/app/javascript/alchemy_admin/components/element_editor/publish_element_button.js +4 -2
- data/app/javascript/alchemy_admin/components/element_editor.js +21 -13
- data/app/javascript/alchemy_admin/components/elements_window.js +87 -0
- data/app/javascript/alchemy_admin/components/growl.js +13 -0
- data/app/javascript/alchemy_admin/components/icon.js +51 -0
- data/app/javascript/alchemy_admin/components/index.js +24 -0
- data/app/javascript/alchemy_admin/components/ingredient_group.js +6 -0
- data/app/javascript/alchemy_admin/components/link_buttons/link_button.js +21 -11
- data/app/javascript/alchemy_admin/components/link_buttons/unlink_button.js +2 -1
- data/app/javascript/alchemy_admin/components/link_buttons.js +1 -0
- data/app/javascript/alchemy_admin/components/list_filter.js +68 -0
- data/app/javascript/alchemy_admin/components/message.js +69 -0
- data/app/javascript/alchemy_admin/components/node_select.js +1 -1
- data/app/javascript/alchemy_admin/components/overlay.js +6 -6
- data/app/javascript/alchemy_admin/components/page_select.js +3 -7
- data/app/javascript/alchemy_admin/components/preview_window.js +121 -0
- data/app/javascript/alchemy_admin/components/remote_select.js +4 -1
- data/app/javascript/alchemy_admin/components/select.js +37 -1
- data/app/javascript/alchemy_admin/components/tags_autocomplete.js +57 -0
- data/app/javascript/alchemy_admin/components/uploader/file_upload.js +4 -3
- data/app/javascript/alchemy_admin/components/uploader/progress.js +1 -1
- data/app/javascript/alchemy_admin/confirm_dialog.js +133 -0
- data/app/javascript/alchemy_admin/dirty.js +19 -14
- data/app/javascript/alchemy_admin/fixed_elements.js +24 -0
- data/app/javascript/alchemy_admin/growler.js +15 -0
- data/app/javascript/alchemy_admin/gui.js +2 -4
- data/app/javascript/alchemy_admin/hotkeys.js +60 -0
- data/app/javascript/alchemy_admin/image_loader.js +2 -2
- data/app/javascript/alchemy_admin/ingredient_anchor_link.js +2 -3
- data/app/javascript/alchemy_admin/initializer.js +1 -8
- data/app/javascript/alchemy_admin/link_dialog.js +131 -0
- data/app/javascript/alchemy_admin/locales/en.js +3 -0
- data/app/javascript/alchemy_admin/node_tree.js +4 -3
- data/app/javascript/alchemy_admin/page_sorter.js +23 -14
- data/app/javascript/alchemy_admin/picture_editors.js +6 -5
- data/app/javascript/alchemy_admin/shoelace_theme.js +60 -0
- data/app/javascript/alchemy_admin/sitemap.js +9 -3
- data/app/javascript/alchemy_admin/sortable_elements.js +4 -6
- data/app/javascript/alchemy_admin.js +18 -42
- data/app/models/alchemy/current.rb +26 -0
- data/app/models/alchemy/element.rb +1 -1
- data/app/models/alchemy/ingredients/audio.rb +0 -11
- data/app/models/alchemy/ingredients/headline.rb +8 -1
- data/app/models/alchemy/ingredients/picture.rb +6 -0
- data/app/models/alchemy/ingredients/video.rb +0 -12
- data/app/models/alchemy/language.rb +8 -6
- data/app/models/alchemy/node.rb +2 -2
- data/app/models/alchemy/page/page_elements.rb +8 -8
- data/app/models/alchemy/page/page_layouts.rb +3 -3
- data/app/models/alchemy/page/page_natures.rb +13 -9
- data/app/models/alchemy/page/page_scopes.rb +2 -2
- data/app/models/alchemy/page/publisher.rb +1 -0
- data/app/models/alchemy/page.rb +13 -28
- data/app/models/alchemy/picture.rb +8 -0
- data/app/models/alchemy/picture_description.rb +8 -0
- data/app/models/alchemy/picture_variant.rb +1 -1
- data/app/models/alchemy/site.rb +10 -7
- data/app/serializers/alchemy/attachment_serializer.rb +8 -0
- data/app/serializers/alchemy/page_node_serializer.rb +9 -0
- data/app/views/alchemy/_menubar.html.erb +1 -1
- data/app/views/alchemy/_preview_mode_code.html.erb +1 -1
- data/app/views/alchemy/admin/attachments/_tag_list.html.erb +2 -2
- data/app/views/alchemy/admin/attachments/archive_overlay.js.erb +0 -1
- data/app/views/alchemy/admin/attachments/edit.html.erb +3 -4
- data/app/views/alchemy/admin/clipboard/clear.js.erb +1 -1
- data/app/views/alchemy/admin/clipboard/index.html.erb +1 -1
- data/app/views/alchemy/admin/clipboard/insert.js.erb +1 -1
- data/app/views/alchemy/admin/clipboard/remove.js.erb +1 -1
- data/app/views/alchemy/admin/dashboard/_locked_pages.html.erb +1 -1
- data/app/views/alchemy/admin/dashboard/_sites.html.erb +1 -1
- data/app/views/alchemy/admin/dashboard/help.html.erb +48 -12
- data/app/views/alchemy/admin/dashboard/index.html.erb +1 -1
- data/app/views/alchemy/admin/dashboard/info.html.erb +5 -8
- data/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb +1 -1
- data/app/views/alchemy/admin/elements/_element.html.erb +5 -5
- data/app/views/alchemy/admin/elements/_footer.html.erb +1 -1
- data/app/views/alchemy/admin/elements/_header.html.erb +6 -2
- data/app/views/alchemy/admin/elements/_toolbar.html.erb +8 -6
- data/app/views/alchemy/admin/elements/create.js.erb +0 -5
- data/app/views/alchemy/admin/elements/index.html.erb +70 -34
- data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +1 -2
- data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +3 -5
- data/app/views/alchemy/admin/languages/_language.html.erb +1 -1
- data/app/views/alchemy/admin/languages/index.html.erb +2 -2
- data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +18 -18
- data/app/views/alchemy/admin/layoutpages/edit.html.erb +4 -5
- data/app/views/alchemy/admin/layoutpages/index.html.erb +2 -2
- data/app/views/alchemy/admin/legacy_page_urls/_legacy_page_url.html.erb +10 -11
- data/app/views/alchemy/admin/legacy_page_urls/_new.html.erb +15 -17
- data/app/views/alchemy/admin/legacy_page_urls/_table.html.erb +16 -0
- data/app/views/alchemy/admin/legacy_page_urls/_update.turbo_stream.erb +12 -0
- data/app/views/alchemy/admin/legacy_page_urls/create.turbo_stream.erb +8 -0
- data/app/views/alchemy/admin/legacy_page_urls/destroy.turbo_stream.erb +1 -0
- data/app/views/alchemy/admin/legacy_page_urls/edit.html.erb +27 -0
- data/app/views/alchemy/admin/legacy_page_urls/show.html.erb +1 -0
- data/app/views/alchemy/admin/legacy_page_urls/update.turbo_stream.erb +1 -0
- data/app/views/alchemy/admin/nodes/_form.html.erb +12 -11
- data/app/views/alchemy/admin/nodes/_label.html.erb +1 -0
- data/app/views/alchemy/admin/nodes/_node.html.erb +19 -19
- data/app/views/alchemy/admin/nodes/_page_nodes.html.erb +48 -0
- data/app/views/alchemy/admin/nodes/_update.turbo_stream.erb +9 -0
- data/app/views/alchemy/admin/nodes/create.turbo_stream.erb +1 -0
- data/app/views/alchemy/admin/nodes/destroy.turbo_stream.erb +1 -0
- data/app/views/alchemy/admin/nodes/index.html.erb +3 -3
- data/app/views/alchemy/admin/pages/_form.html.erb +3 -4
- data/app/views/alchemy/admin/pages/_legacy_urls.html.erb +4 -15
- data/app/views/alchemy/admin/pages/_page.html.erb +39 -39
- data/app/views/alchemy/admin/pages/_table_row.html.erb +3 -3
- data/app/views/alchemy/admin/pages/_toolbar.html.erb +2 -2
- data/app/views/alchemy/admin/pages/configure.html.erb +6 -0
- data/app/views/alchemy/admin/pages/edit.html.erb +15 -62
- data/app/views/alchemy/admin/pages/unlock.js.erb +3 -3
- data/app/views/alchemy/admin/partials/_autocomplete_tag_list.html.erb +3 -1
- data/app/views/alchemy/admin/partials/_flash_notices.html.erb +4 -2
- data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +1 -1
- data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +5 -2
- data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +2 -2
- data/app/views/alchemy/admin/partials/_search_form.html.erb +2 -2
- data/app/views/alchemy/admin/partials/_site_select.html.erb +1 -1
- data/app/views/alchemy/admin/picture_descriptions/_form.html.erb +11 -0
- data/app/views/alchemy/admin/picture_descriptions/edit.html.erb +6 -0
- data/app/views/alchemy/admin/pictures/_form.html.erb +4 -3
- data/app/views/alchemy/admin/pictures/_infos.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_picture_description_field.html.erb +29 -0
- data/app/views/alchemy/admin/pictures/_tag_list.html.erb +2 -2
- data/app/views/alchemy/admin/pictures/archive_overlay.js.erb +0 -2
- data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +3 -3
- data/app/views/alchemy/admin/pictures/show.html.erb +3 -3
- data/app/views/alchemy/admin/resources/_form.html.erb +3 -4
- data/app/views/alchemy/admin/resources/_per_page_select.html.erb +1 -1
- data/app/views/alchemy/admin/resources/_tag_list.html.erb +2 -2
- data/app/views/alchemy/admin/resources/index.html.erb +2 -2
- data/app/views/alchemy/admin/sites/index.html.erb +1 -1
- data/app/views/alchemy/admin/styleguide/index.html.erb +29 -24
- data/app/views/alchemy/admin/tags/_tag.html.erb +1 -1
- data/app/views/alchemy/admin/tags/edit.html.erb +1 -1
- data/app/views/alchemy/admin/tags/index.html.erb +1 -1
- data/app/views/alchemy/base/500.html.erb +7 -18
- data/app/views/alchemy/base/error_notice.html.erb +3 -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/_headline_editor.html.erb +13 -8
- data/app/views/alchemy/ingredients/_picture_editor.html.erb +1 -1
- data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +1 -1
- data/app/views/alchemy/language_links/_language.html.erb +1 -1
- data/app/views/kaminari/alchemy/_first_page.html.erb +2 -2
- data/app/views/kaminari/alchemy/_gap.html.erb +1 -1
- data/app/views/kaminari/alchemy/_last_page.html.erb +2 -2
- data/app/views/kaminari/alchemy/_next_page.html.erb +2 -2
- data/app/views/kaminari/alchemy/_prev_page.html.erb +2 -2
- data/app/views/layouts/alchemy/admin.html.erb +2 -1
- data/bundles/shoelace.js +3 -1
- data/config/locales/alchemy.en.yml +16 -3
- data/config/routes.rb +4 -2
- data/db/migrate/20240314105244_create_alchemy_picture_descriptions.rb +11 -0
- data/lib/alchemy/configuration_methods.rb +1 -1
- data/lib/alchemy/controller_actions.rb +3 -3
- data/lib/alchemy/element_definition.rb +10 -6
- data/lib/alchemy/engine.rb +19 -2
- data/lib/alchemy/page_layout.rb +10 -6
- data/lib/alchemy/permissions.rb +4 -3
- data/lib/alchemy/routing_constraints.rb +1 -1
- data/lib/alchemy/seeder.rb +2 -2
- data/lib/alchemy/test_support/capybara_helpers.rb +4 -0
- data/lib/alchemy/test_support/factories/language_factory.rb +1 -1
- data/lib/alchemy/test_support/shared_contexts.rb +8 -0
- data/lib/alchemy/tinymce.rb +2 -1
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy.rb +36 -0
- data/lib/alchemy_cms.rb +0 -1
- data/lib/generators/alchemy/menus/templates/node.html.erb +2 -2
- data/lib/generators/alchemy/menus/templates/node.html.haml +2 -2
- data/lib/generators/alchemy/menus/templates/node.html.slim +2 -2
- data/lib/generators/alchemy/menus/templates/wrapper.html.erb +1 -1
- data/lib/generators/alchemy/menus/templates/wrapper.html.haml +1 -1
- data/lib/generators/alchemy/menus/templates/wrapper.html.slim +1 -1
- data/lib/tasks/alchemy/sitemap.rake +97 -0
- data/lib/tasks/alchemy/tidy.rake +1 -0
- data/package.json +8 -8
- data/vendor/assets/fonts/remixicon.symbol.svg +11 -0
- data/vendor/javascript/shoelace.min.js +333 -118
- data/vendor/javascript/sortable.min.js +1 -1
- data/vendor/javascript/tinymce.min.js +1 -1
- data/vendor/javascript/ungap-custom-elements.min.js +1 -1
- metadata +61 -55
- data/app/assets/javascripts/alchemy/alchemy.confirm_dialog.js.coffee +0 -85
- data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +0 -107
- data/app/assets/javascripts/alchemy/alchemy.file_progress.js.coffee +0 -66
- data/app/assets/javascripts/alchemy/alchemy.fixed_elements.js +0 -45
- data/app/assets/javascripts/alchemy/alchemy.growler.js.coffee +0 -24
- data/app/assets/javascripts/alchemy/alchemy.hotkeys.js.coffee +0 -49
- data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +0 -0
- data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +0 -230
- data/app/assets/javascripts/alchemy/alchemy.list_filter.js.coffee +0 -49
- data/app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee +0 -82
- data/app/assets/javascripts/alchemy/alchemy.string_extension.js.coffee +0 -11
- data/app/assets/javascripts/alchemy/templates/page.hbs +0 -19
- data/app/javascript/alchemy_admin/tags_autocomplete.js +0 -46
- data/app/models/alchemy/tree_node.rb +0 -7
- data/app/views/alchemy/admin/elements/destroy.js.erb +0 -8
- data/app/views/alchemy/admin/legacy_page_urls/_form.html.erb +0 -5
- data/app/views/alchemy/admin/legacy_page_urls/create.js.erb +0 -9
- data/app/views/alchemy/admin/legacy_page_urls/destroy.js.erb +0 -6
- data/app/views/alchemy/admin/legacy_page_urls/update.js.erb +0 -2
- data/app/views/alchemy/admin/pages/_anchor_link.html.erb +0 -22
- data/app/views/alchemy/admin/pages/_external_link.html.erb +0 -31
- data/app/views/alchemy/admin/pages/_file_link.html.erb +0 -31
- data/app/views/alchemy/admin/pages/_internal_link.html.erb +0 -35
- data/app/views/alchemy/admin/pages/link.html.erb +0 -26
- data/app/views/alchemy/admin/partials/_flash.html.erb +0 -4
- data/app/views/alchemy/admin/partials/_toolbar_button.html.erb +0 -29
- data/lib/alchemy/test_support/current_language_shared_examples.rb +0 -33
- data/vendor/assets/fonts/remixicon.eot +0 -0
- data/vendor/assets/fonts/remixicon.svg +0 -7816
- 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 +0 -10480
@@ -0,0 +1,133 @@
|
|
1
|
+
import { growl } from "alchemy_admin/growler"
|
2
|
+
import pleaseWaitOverlay from "alchemy_admin/please_wait_overlay"
|
3
|
+
import { createHtmlElement } from "alchemy_admin/utils/dom_helpers"
|
4
|
+
import { translate } from "alchemy_admin/i18n"
|
5
|
+
|
6
|
+
class ConfirmDialog {
|
7
|
+
constructor(message, options = {}) {
|
8
|
+
const DEFAULTS = {
|
9
|
+
size: "300x100",
|
10
|
+
title: translate("Please confirm"),
|
11
|
+
ok_label: translate("Yes"),
|
12
|
+
cancel_label: translate("No"),
|
13
|
+
on_ok() {}
|
14
|
+
}
|
15
|
+
|
16
|
+
options = { ...DEFAULTS, ...options }
|
17
|
+
|
18
|
+
this.message = message
|
19
|
+
this.options = options
|
20
|
+
this.#build()
|
21
|
+
this.#bindEvents()
|
22
|
+
}
|
23
|
+
|
24
|
+
open() {
|
25
|
+
requestAnimationFrame(() => {
|
26
|
+
this.dialog.show()
|
27
|
+
})
|
28
|
+
}
|
29
|
+
|
30
|
+
#build() {
|
31
|
+
const width = this.options.size.split("x")[0]
|
32
|
+
this.dialog = createHtmlElement(`
|
33
|
+
<sl-dialog label="${this.options.title}" style="--width: ${width}px">
|
34
|
+
${this.message}
|
35
|
+
<button slot="footer" type="reset" class="secondary mx-1 my-0" autofocus>
|
36
|
+
${this.options.cancel_label}
|
37
|
+
</button>
|
38
|
+
<button slot="footer" type="submit" class="mx-1 my-0">
|
39
|
+
${this.options.ok_label}
|
40
|
+
</button>
|
41
|
+
</sl-dialog>
|
42
|
+
`)
|
43
|
+
document.body.append(this.dialog)
|
44
|
+
}
|
45
|
+
|
46
|
+
#bindEvents() {
|
47
|
+
this.cancelButton.addEventListener("click", (evt) => {
|
48
|
+
evt.preventDefault()
|
49
|
+
this.dialog.hide()
|
50
|
+
})
|
51
|
+
this.okButton.addEventListener("click", (evt) => {
|
52
|
+
evt.preventDefault()
|
53
|
+
this.options.on_ok()
|
54
|
+
this.dialog.hide()
|
55
|
+
})
|
56
|
+
// Prevent the dialog from closing when the user clicks on the overlay
|
57
|
+
this.dialog.addEventListener("sl-request-close", (event) => {
|
58
|
+
if (event.detail.source === "overlay") {
|
59
|
+
event.preventDefault()
|
60
|
+
}
|
61
|
+
})
|
62
|
+
// Remove the dialog from the DOM after it has been hidden
|
63
|
+
this.dialog.addEventListener("sl-after-hide", () => {
|
64
|
+
this.dialog.remove()
|
65
|
+
})
|
66
|
+
}
|
67
|
+
|
68
|
+
get cancelButton() {
|
69
|
+
return this.dialog.querySelector("button[type=reset]")
|
70
|
+
}
|
71
|
+
|
72
|
+
get okButton() {
|
73
|
+
return this.dialog.querySelector("button[type=submit]")
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
// Opens a confirm dialog
|
78
|
+
//
|
79
|
+
// Arguments:
|
80
|
+
//
|
81
|
+
// message - The message that will be displayed to the user (String)
|
82
|
+
//
|
83
|
+
// Options:
|
84
|
+
//
|
85
|
+
// title: '' - The title of the overlay window (String)
|
86
|
+
// cancel_label: '' - The label of the cancel button (String)
|
87
|
+
// ok_label: '' - The label of the ok button (String)
|
88
|
+
// on_ok: null - The function to invoke on confirmation (Function)
|
89
|
+
//
|
90
|
+
export function openConfirmDialog(message, options = {}) {
|
91
|
+
const dialog = new ConfirmDialog(message, options)
|
92
|
+
dialog.open()
|
93
|
+
return dialog
|
94
|
+
}
|
95
|
+
|
96
|
+
// Opens a confirm to delete dialog
|
97
|
+
//
|
98
|
+
// Arguments:
|
99
|
+
//
|
100
|
+
// url - The url to the server delete action. Uses DELETE as HTTP method. (String)
|
101
|
+
// opts - An options object (Object)
|
102
|
+
//
|
103
|
+
// Options:
|
104
|
+
//
|
105
|
+
// title: '' - The title of the confirmation window (String)
|
106
|
+
// message: '' - The message that will be displayed to the user (String)
|
107
|
+
// ok_label: '' - The label for the ok button (String)
|
108
|
+
// cancel_label: '' - The label for the cancel button (String)
|
109
|
+
//
|
110
|
+
export function confirmToDeleteDialog(url, opts = {}) {
|
111
|
+
return new Promise((resolve, reject) => {
|
112
|
+
const options = {
|
113
|
+
on_ok() {
|
114
|
+
pleaseWaitOverlay()
|
115
|
+
$.ajax({
|
116
|
+
url,
|
117
|
+
type: "DELETE",
|
118
|
+
error(xhr, _status, error) {
|
119
|
+
const type = xhr.status === 403 ? "warning" : "error"
|
120
|
+
growl(xhr.responseText || error, type)
|
121
|
+
reject(error)
|
122
|
+
},
|
123
|
+
complete(response) {
|
124
|
+
pleaseWaitOverlay(false)
|
125
|
+
resolve(response)
|
126
|
+
}
|
127
|
+
})
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
openConfirmDialog(opts.message, { ...options, ...opts })
|
132
|
+
})
|
133
|
+
}
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
import { openConfirmDialog } from "alchemy_admin/confirm_dialog"
|
2
|
+
import { translate } from "alchemy_admin/i18n"
|
3
|
+
import pleaseWaitOverlay from "alchemy_admin/please_wait_overlay"
|
4
4
|
|
5
5
|
function checkPageDirtyness(element) {
|
6
6
|
let callback = () => {}
|
@@ -13,18 +13,21 @@ function checkPageDirtyness(element) {
|
|
13
13
|
$form.append($(element).find("input"))
|
14
14
|
$form.appendTo("body")
|
15
15
|
|
16
|
-
|
17
|
-
$form.submit
|
16
|
+
pleaseWaitOverlay()
|
17
|
+
$form.trigger("submit")
|
18
18
|
}
|
19
19
|
} else if ($(element).is("a")) {
|
20
20
|
callback = () => Turbo.visit(element.pathname)
|
21
21
|
}
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
const isPageDirty =
|
24
|
+
document.querySelectorAll("alchemy-element-editor.dirty").length > 0
|
25
|
+
|
26
|
+
if (isPageDirty) {
|
27
|
+
openConfirmDialog(translate("page_dirty_notice"), {
|
28
|
+
title: translate("warning"),
|
29
|
+
ok_label: translate("ok"),
|
30
|
+
cancel_label: translate("cancel"),
|
28
31
|
on_ok: function () {
|
29
32
|
window.onbeforeunload = void 0
|
30
33
|
callback()
|
@@ -36,10 +39,12 @@ function checkPageDirtyness(element) {
|
|
36
39
|
}
|
37
40
|
|
38
41
|
function PageLeaveObserver() {
|
39
|
-
|
40
|
-
|
41
|
-
event.
|
42
|
-
|
42
|
+
document.querySelectorAll("#main_navi a").forEach((element) => {
|
43
|
+
element.addEventListener("click", (event) => {
|
44
|
+
if (!checkPageDirtyness(event.currentTarget)) {
|
45
|
+
event.preventDefault()
|
46
|
+
}
|
47
|
+
})
|
43
48
|
})
|
44
49
|
}
|
45
50
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
// Creates a fixed element tab.
|
2
|
+
export function createTab(element_id, label) {
|
3
|
+
const fixed_elements = document.getElementById("fixed-elements")
|
4
|
+
const panel_name = `fixed-element-${element_id}`
|
5
|
+
|
6
|
+
const tab = `<sl-tab slot="nav" panel="${panel_name}">${label}</sl-tab>`
|
7
|
+
const panel = `<sl-tab-panel name="${panel_name}" style="--padding: 0" />`
|
8
|
+
|
9
|
+
fixed_elements.innerHTML += tab + panel
|
10
|
+
|
11
|
+
window.requestAnimationFrame(function () {
|
12
|
+
fixed_elements.show(panel_name)
|
13
|
+
})
|
14
|
+
}
|
15
|
+
|
16
|
+
export function removeTab(element_id) {
|
17
|
+
const fixed_elements = document.getElementById("fixed-elements")
|
18
|
+
const panel_name = `fixed-element-${element_id}`
|
19
|
+
|
20
|
+
fixed_elements.querySelector(`sl-tab[panel="${panel_name}"]`).remove()
|
21
|
+
fixed_elements.querySelector(`sl-tab-panel[name="${panel_name}"]`).remove()
|
22
|
+
|
23
|
+
fixed_elements.show("main-content-elements")
|
24
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { createHtmlElement } from "alchemy_admin/utils/dom_helpers"
|
2
|
+
|
3
|
+
function build(message, flashType) {
|
4
|
+
const flashNotices = document.getElementById("flash_notices")
|
5
|
+
const flashMessage = createHtmlElement(`
|
6
|
+
<alchemy-message type="${flashType}" dismissable>
|
7
|
+
${message}
|
8
|
+
</alchemy-message>
|
9
|
+
`)
|
10
|
+
flashNotices.append(flashMessage)
|
11
|
+
}
|
12
|
+
|
13
|
+
export function growl(message, style = "notice") {
|
14
|
+
build(message, style)
|
15
|
+
}
|
@@ -1,12 +1,10 @@
|
|
1
|
-
import
|
1
|
+
import Hotkeys from "alchemy_admin/hotkeys"
|
2
2
|
|
3
3
|
function init(scope) {
|
4
4
|
if (!scope) {
|
5
5
|
Alchemy.watchForDialogs()
|
6
6
|
}
|
7
|
-
|
8
|
-
Alchemy.ListFilter(scope)
|
9
|
-
TagsAutocomplete(scope)
|
7
|
+
Hotkeys(scope)
|
10
8
|
}
|
11
9
|
|
12
10
|
export default {
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import "keymaster"
|
2
|
+
|
3
|
+
const bindedHotkeys = []
|
4
|
+
|
5
|
+
function showHelp(evt) {
|
6
|
+
if (
|
7
|
+
!$(evt.target).is("input, textarea") &&
|
8
|
+
String.fromCharCode(evt.which) === "?"
|
9
|
+
) {
|
10
|
+
Alchemy.openDialog("/admin/help", {
|
11
|
+
title: Alchemy.t("help"),
|
12
|
+
size: "400x492"
|
13
|
+
})
|
14
|
+
return false
|
15
|
+
} else {
|
16
|
+
return true
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
export default function (scope = document) {
|
21
|
+
// The scope can be a jQuery object because we still use jQuery in Alchemy.Dialog.
|
22
|
+
if (scope instanceof jQuery) {
|
23
|
+
scope = scope[0]
|
24
|
+
}
|
25
|
+
|
26
|
+
// Unbind all previously registered hotkeys if we are not inside a dialog.
|
27
|
+
if (scope === document) {
|
28
|
+
document.removeEventListener("keypress", showHelp)
|
29
|
+
document.addEventListener("keypress", showHelp)
|
30
|
+
bindedHotkeys.forEach((hotkey) => key.unbind(hotkey))
|
31
|
+
}
|
32
|
+
|
33
|
+
// Binds keyboard shortcuts to search fields.
|
34
|
+
const search_fields = scope.querySelectorAll(".search_input_field")
|
35
|
+
const search_fields_clear = scope.querySelectorAll(
|
36
|
+
".search_field_clear, .js_filter_field_clear"
|
37
|
+
)
|
38
|
+
key("alt+f", function () {
|
39
|
+
key.setScope("search")
|
40
|
+
search_fields.forEach((el) => el.focus({ focusVisible: true }))
|
41
|
+
return false
|
42
|
+
})
|
43
|
+
bindedHotkeys.push("alt+f")
|
44
|
+
key("esc", "search", function () {
|
45
|
+
search_fields_clear.forEach((el) => el.click())
|
46
|
+
search_fields.forEach((el) => el.blur())
|
47
|
+
})
|
48
|
+
bindedHotkeys.push("esc")
|
49
|
+
|
50
|
+
// Binds click events to buttons with hotkeys.
|
51
|
+
//
|
52
|
+
// Simply add a data-alchemy-hotkey attribute to your link.
|
53
|
+
// If a hotkey is triggered by user, the click event of the element gets triggerd.
|
54
|
+
//
|
55
|
+
scope.querySelectorAll("[data-alchemy-hotkey]").forEach(function (el) {
|
56
|
+
const hotkey = el.dataset.alchemyHotkey
|
57
|
+
key(hotkey, () => el.click())
|
58
|
+
bindedHotkeys.push(hotkey)
|
59
|
+
})
|
60
|
+
}
|
@@ -38,9 +38,9 @@ export default class ImageLoader {
|
|
38
38
|
}
|
39
39
|
|
40
40
|
onError(evt) {
|
41
|
-
const message = `Could not load
|
41
|
+
const message = `Could not load ${this.image.src}`
|
42
42
|
this.spinner.stop()
|
43
|
-
this.parent.innerHTML = `<
|
43
|
+
this.parent.innerHTML = `<alchemy-icon name="alert" class="error" title="${message}" />`
|
44
44
|
console.error(message, evt)
|
45
45
|
this.unbind()
|
46
46
|
}
|
@@ -5,10 +5,9 @@ export default class IngredientAnchorLink {
|
|
5
5
|
)
|
6
6
|
if (ingredientEditor) {
|
7
7
|
const icon = ingredientEditor.querySelector(
|
8
|
-
".edit-ingredient-anchor-link
|
8
|
+
".edit-ingredient-anchor-link alchemy-icon"
|
9
9
|
)
|
10
|
-
icon
|
11
|
-
icon?.classList.toggle("ri-bookmark-line", !active)
|
10
|
+
icon.setAttribute("icon-style", active ? "fill" : "line")
|
12
11
|
}
|
13
12
|
}
|
14
13
|
}
|
@@ -18,18 +18,13 @@ function selectHandler(selectId, parameterName, forcedReload = false) {
|
|
18
18
|
})
|
19
19
|
}
|
20
20
|
|
21
|
-
function
|
21
|
+
export default function Initializer() {
|
22
22
|
// We obviously have javascript enabled.
|
23
23
|
$("html").removeClass("no-js")
|
24
24
|
|
25
25
|
// Initialize the GUI.
|
26
26
|
Alchemy.GUI.init()
|
27
27
|
|
28
|
-
// Fade all growl notifications.
|
29
|
-
if ($("#flash_notices").length > 0) {
|
30
|
-
Alchemy.Growler.fade()
|
31
|
-
}
|
32
|
-
|
33
28
|
// Add observer for please wait overlay.
|
34
29
|
$(".please_wait")
|
35
30
|
.not("*[data-alchemy-confirm]")
|
@@ -61,5 +56,3 @@ function Initialize() {
|
|
61
56
|
)
|
62
57
|
}
|
63
58
|
}
|
64
|
-
|
65
|
-
export default Initialize
|
@@ -0,0 +1,131 @@
|
|
1
|
+
import { translate } from "alchemy_admin/i18n"
|
2
|
+
|
3
|
+
// Represents the link Dialog that appears, if a user clicks the link buttons
|
4
|
+
// in TinyMCE or on an Ingredient that has links enabled (e.g. Picture)
|
5
|
+
//
|
6
|
+
export class LinkDialog extends Alchemy.Dialog {
|
7
|
+
#onCreateLink
|
8
|
+
|
9
|
+
constructor(link) {
|
10
|
+
const url = new URL(Alchemy.routes.link_admin_pages_path, window.location)
|
11
|
+
const parameterMapping = {
|
12
|
+
url: link.url,
|
13
|
+
selected_tab: link.type,
|
14
|
+
link_title: link.title,
|
15
|
+
link_target: link.target
|
16
|
+
}
|
17
|
+
|
18
|
+
// searchParams.set would also add undefined values
|
19
|
+
Object.keys(parameterMapping).forEach((key) => {
|
20
|
+
if (parameterMapping[key]) {
|
21
|
+
url.searchParams.set(key, parameterMapping[key])
|
22
|
+
}
|
23
|
+
})
|
24
|
+
|
25
|
+
super(url.href, {
|
26
|
+
size: "600x320",
|
27
|
+
title: translate("Link")
|
28
|
+
})
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Called from Dialog class after the url was loaded
|
33
|
+
*/
|
34
|
+
replace(data) {
|
35
|
+
// let Dialog class handle the content replacement
|
36
|
+
super.replace(data)
|
37
|
+
this.#attachEvents()
|
38
|
+
}
|
39
|
+
|
40
|
+
/**
|
41
|
+
* make the open method a promise
|
42
|
+
* maybe in a future version the whole Dialog will respond with a promise result if the dialog is closing
|
43
|
+
* @returns {Promise<unknown>}
|
44
|
+
*/
|
45
|
+
open() {
|
46
|
+
super.open()
|
47
|
+
return new Promise((resolve) => (this.#onCreateLink = resolve))
|
48
|
+
}
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Attaches click events to forms in the link dialog.
|
52
|
+
*/
|
53
|
+
#attachEvents() {
|
54
|
+
// enable the dom selection in internal link tab
|
55
|
+
const internalForm = document.querySelector(
|
56
|
+
'[data-link-form-type="internal"]'
|
57
|
+
)
|
58
|
+
const attachmentSelect = document.querySelector(
|
59
|
+
'[data-link-form-type="file"] alchemy-attachment-select'
|
60
|
+
)
|
61
|
+
|
62
|
+
internalForm.addEventListener("Alchemy.RemoteSelect.Change", (e) => {
|
63
|
+
this.#updatePage(e.detail.added)
|
64
|
+
})
|
65
|
+
|
66
|
+
attachmentSelect.addEventListener("Alchemy.RemoteSelect.Change", (e) => {
|
67
|
+
const attachment = e.detail.added
|
68
|
+
document.getElementById("file_link").value = attachment
|
69
|
+
? attachment.url
|
70
|
+
: ""
|
71
|
+
})
|
72
|
+
|
73
|
+
document.querySelectorAll("[data-link-form-type]").forEach((form) => {
|
74
|
+
form.addEventListener("submit", (e) => {
|
75
|
+
e.preventDefault()
|
76
|
+
this.#submitForm(e.target.dataset.linkFormType)
|
77
|
+
})
|
78
|
+
})
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* update page select and set anchor select
|
83
|
+
* @param page
|
84
|
+
*/
|
85
|
+
#updatePage(page = null) {
|
86
|
+
const internalLink = document.getElementById("internal_link")
|
87
|
+
const domIdSelect = document.querySelector(
|
88
|
+
'[data-link-form-type="internal"] alchemy-dom-id-api-select'
|
89
|
+
)
|
90
|
+
|
91
|
+
internalLink.value = page ? page.url_path : ""
|
92
|
+
domIdSelect.page = page ? page.id : undefined
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* submit the form itself
|
97
|
+
* @param linkType
|
98
|
+
*/
|
99
|
+
#submitForm(linkType) {
|
100
|
+
const elementAnchor = document.getElementById("element_anchor")
|
101
|
+
let url = document.getElementById(`${linkType}_link`).value
|
102
|
+
|
103
|
+
if (linkType === "internal" && elementAnchor.value !== "") {
|
104
|
+
// remove possible fragments on the url and attach the fragment (which contains the #)
|
105
|
+
url = url.replace(/#\w+$/, "") + elementAnchor.value
|
106
|
+
} else if (linkType === "external" && !url.match(Alchemy.link_url_regexp)) {
|
107
|
+
// show validation error and prevent link creation
|
108
|
+
this.#showValidationError()
|
109
|
+
return
|
110
|
+
}
|
111
|
+
|
112
|
+
// Create the link
|
113
|
+
this.#onCreateLink({
|
114
|
+
url: url.trim(),
|
115
|
+
title: document.getElementById(`${linkType}_link_title`).value,
|
116
|
+
target: document.getElementById(`${linkType}_link_target`)?.value,
|
117
|
+
type: linkType
|
118
|
+
})
|
119
|
+
this.close()
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* Shows validation errors
|
124
|
+
*/
|
125
|
+
#showValidationError() {
|
126
|
+
const errors = document.getElementById("errors")
|
127
|
+
errors.querySelector("ul").innerHTML =
|
128
|
+
`<li>${Alchemy.t("url_validation_failed")}</li>`
|
129
|
+
errors.style.display = "block"
|
130
|
+
}
|
131
|
+
}
|
@@ -21,6 +21,9 @@ export const en = {
|
|
21
21
|
"Uploaded bytes exceed file size": "Uploaded bytes exceed file size",
|
22
22
|
"Abort upload": "Abort upload",
|
23
23
|
"Cancel all uploads": "Cancel all uploads",
|
24
|
+
None: "None",
|
25
|
+
"No anchors found": "No anchors found",
|
26
|
+
"Select a page first": "Select a page first",
|
24
27
|
Close: "Close",
|
25
28
|
formats: {
|
26
29
|
datetime: "Y-m-d H:i",
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import Sortable from "sortablejs"
|
2
2
|
import { patch } from "alchemy_admin/utils/ajax"
|
3
3
|
import { on } from "alchemy_admin/utils/events"
|
4
|
+
import { growl } from "alchemy_admin/growler"
|
4
5
|
|
5
6
|
function displayNodeFolders() {
|
6
7
|
document.querySelectorAll("li.menu-item").forEach((el) => {
|
@@ -32,11 +33,11 @@ function onFinishDragging(evt) {
|
|
32
33
|
patch(url, data)
|
33
34
|
.then(() => {
|
34
35
|
const message = Alchemy.t("Successfully moved menu item")
|
35
|
-
|
36
|
+
growl(message)
|
36
37
|
displayNodeFolders()
|
37
38
|
})
|
38
39
|
.catch((error) => {
|
39
|
-
|
40
|
+
growl(error.message || error, "error")
|
40
41
|
})
|
41
42
|
}
|
42
43
|
|
@@ -56,7 +57,7 @@ function handleNodeFolders() {
|
|
56
57
|
displayNodeFolders()
|
57
58
|
})
|
58
59
|
.catch((error) => {
|
59
|
-
|
60
|
+
growl(error.message || error)
|
60
61
|
})
|
61
62
|
})
|
62
63
|
}
|
@@ -1,7 +1,9 @@
|
|
1
1
|
import Sortable from "sortablejs"
|
2
|
+
import { growl } from "alchemy_admin/growler"
|
2
3
|
import { patch } from "alchemy_admin/utils/ajax"
|
4
|
+
import pleaseWaitOverlay from "alchemy_admin/please_wait_overlay"
|
3
5
|
|
4
|
-
function
|
6
|
+
function onSort(evt) {
|
5
7
|
const pageId = evt.item.dataset.pageId
|
6
8
|
const url = Alchemy.routes.move_admin_page_path(pageId)
|
7
9
|
const data = {
|
@@ -9,19 +11,26 @@ function onFinishDragging(evt) {
|
|
9
11
|
new_position: evt.newIndex
|
10
12
|
}
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
if (evt.target === evt.to) {
|
15
|
+
pleaseWaitOverlay(true)
|
16
|
+
patch(url, data)
|
17
|
+
.then(async (response) => {
|
18
|
+
const pageData = await response.data
|
19
|
+
const pageEl = document.getElementById(`page_${pageId}`)
|
20
|
+
const urlPathEl = pageEl.querySelector(".sitemap_url")
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
growl(Alchemy.t("Successfully moved page"))
|
23
|
+
urlPathEl.textContent = pageData.url_path
|
24
|
+
displayPageFolders()
|
25
|
+
})
|
26
|
+
.catch((error) => {
|
27
|
+
growl(error.message || error, "error")
|
28
|
+
Alchemy.currentSitemap.reload()
|
29
|
+
})
|
30
|
+
.finally(() => {
|
31
|
+
pleaseWaitOverlay(false)
|
32
|
+
})
|
33
|
+
}
|
25
34
|
}
|
26
35
|
|
27
36
|
export function displayPageFolders() {
|
@@ -50,7 +59,7 @@ export function createSortables(sortables) {
|
|
50
59
|
fallbackOnBody: true,
|
51
60
|
swapThreshold: 0.65,
|
52
61
|
handle: ".handle",
|
53
|
-
|
62
|
+
onSort
|
54
63
|
})
|
55
64
|
})
|
56
65
|
}
|
@@ -1,13 +1,14 @@
|
|
1
1
|
import debounce from "alchemy_admin/utils/debounce"
|
2
2
|
import max from "alchemy_admin/utils/max"
|
3
3
|
import { get } from "alchemy_admin/utils/ajax"
|
4
|
+
import { growl } from "alchemy_admin/growler"
|
4
5
|
import ImageLoader from "alchemy_admin/image_loader"
|
5
6
|
|
6
7
|
const UPDATE_DELAY = 125
|
7
|
-
const IMAGE_PLACEHOLDER = '<
|
8
|
+
const IMAGE_PLACEHOLDER = '<alchemy-icon name="image"></alchemy-icon>'
|
8
9
|
const THUMBNAIL_SIZE = "160x120"
|
9
10
|
|
10
|
-
|
11
|
+
class PictureEditor {
|
11
12
|
constructor(container) {
|
12
13
|
this.container = container
|
13
14
|
this.cropFromField = container.querySelector("[data-crop-from]")
|
@@ -77,7 +78,7 @@ export class PictureEditor {
|
|
77
78
|
})
|
78
79
|
.catch((error) => {
|
79
80
|
console.error(error.message || error)
|
80
|
-
|
81
|
+
growl(error.message || error, "error")
|
81
82
|
})
|
82
83
|
}
|
83
84
|
|
@@ -131,10 +132,10 @@ export class PictureEditor {
|
|
131
132
|
if (!this.imageCropperEnabled) return []
|
132
133
|
|
133
134
|
const mask = this.targetSize.split("x").map((n) => parseInt(n))
|
134
|
-
const zoom = max(
|
135
|
+
const zoom = max([
|
135
136
|
mask[0] / this.imageFileWidth,
|
136
137
|
mask[1] / this.imageFileHeight
|
137
|
-
)
|
138
|
+
])
|
138
139
|
|
139
140
|
return [Math.round(mask[0] / zoom), Math.round(mask[1] / zoom)]
|
140
141
|
}
|