{"version":3,"file":"alchemy_admin.min.js","sources":["../../../javascript/alchemy_admin/i18n.js","../../../javascript/alchemy_admin/hotkeys.js","../../../javascript/alchemy_admin/utils/dom_helpers.js","../../../javascript/alchemy_admin/spinner.js","../../../javascript/alchemy_admin/dialog.js","../../../javascript/alchemy_admin/confirm_dialog.js","../../../javascript/alchemy_admin/please_wait_overlay.js","../../../javascript/alchemy_admin/dirty.js","../../../javascript/alchemy_admin/fixed_elements.js","../../../javascript/alchemy_admin/growler.js","../../../javascript/alchemy_admin/link_dialog.js","../../../javascript/alchemy_admin/components/preview_window.js","../../../javascript/alchemy_admin/ingredient_anchor_link.js","../../../javascript/alchemy_admin/components/action.js","../../../javascript/alchemy_admin/components/alchemy_html_element.js","../../../javascript/alchemy_admin/utils/string_conversions.js","../../../javascript/alchemy_admin/components/remote_select.js","../../../javascript/alchemy_admin/components/attachment_select.js","../../../javascript/alchemy_admin/components/auto_submit.js","../../../javascript/alchemy_admin/components/button.js","../../../javascript/alchemy_admin/components/char_counter.js","../../../javascript/alchemy_admin/components/clipboard_button.js","../../../javascript/alchemy_admin/components/color_select.js","../../../javascript/alchemy_admin/components/datepicker.js","../../../javascript/alchemy_admin/components/dialog_link.js","../../../javascript/alchemy_admin/utils/ajax.js","../../../javascript/alchemy_admin/components/dom_id_select.js","../../../javascript/alchemy_admin/components/element_editor/publish_element_button.js","../../../javascript/alchemy_admin/components/element_editor/delete_element_button.js","../../../javascript/alchemy_admin/components/element_editor.js","../../../javascript/alchemy_admin/components/element_select.js","../../../javascript/alchemy_admin/components/elements_window.js","../../../javascript/alchemy_admin/components/elements_window_handle.js","../../../javascript/alchemy_admin/components/file_editor.js","../../../javascript/alchemy_admin/components/list_filter.js","../../../javascript/alchemy_admin/components/message.js","../../../javascript/alchemy_admin/components/growl.js","../../../javascript/alchemy_admin/components/icon.js","../../../javascript/alchemy_admin/components/ingredient_group.js","../../../javascript/alchemy_admin/components/link_buttons/link_button.js","../../../javascript/alchemy_admin/components/link_buttons/unlink_button.js","../../../javascript/alchemy_admin/components/link_buttons.js","../../../javascript/alchemy_admin/utils/format.js","../../../javascript/alchemy_admin/components/node_select.js","../../../javascript/alchemy_admin/components/uploader/file_upload.js","../../../javascript/alchemy_admin/components/uploader/progress.js","../../../javascript/alchemy_admin/components/uploader.js","../../../javascript/alchemy_admin/components/overlay.js","../../../javascript/alchemy_admin/components/page_node.js","../../../javascript/alchemy_admin/components/page_publication_fields.js","../../../javascript/alchemy_admin/components/page_select.js","../../../javascript/alchemy_admin/components/picture_description_select.js","../../../javascript/alchemy_admin/components/picture_editor.js","../../../javascript/alchemy_admin/utils/debounce.js","../../../javascript/alchemy_admin/utils/max.js","../../../javascript/alchemy_admin/components/picture_thumbnail.js","../../../javascript/alchemy_admin/components/publish_page_button.js","../../../javascript/alchemy_admin/components/select.js","../../../javascript/alchemy_admin/components/sitemap.js","../../../javascript/alchemy_admin/components/sortable_elements.js","../../../javascript/alchemy_admin/components/spinner.js","../../../javascript/alchemy_admin/components/tags_autocomplete.js","../../../javascript/alchemy_admin/components/tinymce.js","../../../javascript/alchemy_admin/components/update_check.js","../../../javascript/alchemy_admin/templates/compiled.js","../../../javascript/alchemy_admin/shoelace_theme.js","../../../javascript/alchemy_admin/utils/events.js","../../../javascript/alchemy_admin/image_cropper.js","../../../javascript/alchemy_admin/image_overlay.js","../../../javascript/alchemy_admin/picture_selector.js","../../../javascript/alchemy_admin/node_tree.js","../../../javascript/alchemy_admin.js","../../../javascript/alchemy_admin/initializer.js"],"sourcesContent":["const KEY_SEPARATOR = /\\./\n\nfunction nestedTranslation(translations, key) {\n const keys = key.split(KEY_SEPARATOR)\n const group = translations[keys[0]]\n if (group) {\n return group[keys[1]] || key\n }\n return key\n}\n\nfunction getTranslation(key) {\n const locale = currentLocale()\n const translations = Alchemy.translations\n\n if (!translations) {\n console.warn(`Translations for locale ${locale} not found!`)\n return key\n }\n\n if (KEY_SEPARATOR.test(key)) {\n return nestedTranslation(translations, key)\n }\n return translations[key] || key\n}\n\nexport function currentLocale() {\n if (document.documentElement.lang) {\n return document.documentElement.lang\n }\n return \"en\"\n}\n\nexport function translate(key, replacement = undefined) {\n let translation = getTranslation(key)\n\n if (replacement) {\n return translation.replace(/%\\{.+\\}/, replacement)\n }\n return translation\n}\n\nexport async function setupSelectLocale() {\n const locale = currentLocale()\n if (locale === \"en\") return\n\n await import(`select2/${locale}.js`)\n $.extend($.fn.select2.defaults, $.fn.select2.locales[locale])\n}\n","import \"keymaster\"\nimport { openDialog } from \"alchemy_admin/dialog\"\n\nconst bindedHotkeys = []\n\nfunction showHelp(evt) {\n if (\n !$(evt.target).is(\"input, textarea\") &&\n String.fromCharCode(evt.which) === \"?\"\n ) {\n openDialog(\"/admin/help\", {\n title: Alchemy.t(\"help\"),\n size: \"400x492\"\n })\n return false\n } else {\n return true\n }\n}\n\nexport default function (scope = document) {\n // The scope can be a jQuery object because we still use jQuery in alchemy_admin/dialog.js.\n if (scope instanceof jQuery) {\n scope = scope[0]\n }\n\n // Unbind all previously registered hotkeys if we are not inside a dialog.\n if (scope === document) {\n document.removeEventListener(\"keypress\", showHelp)\n document.addEventListener(\"keypress\", showHelp)\n bindedHotkeys.forEach((hotkey) => key.unbind(hotkey))\n }\n\n // Binds keyboard shortcuts to search fields.\n const search_fields = scope.querySelectorAll(\".search_input_field\")\n const search_fields_clear = scope.querySelectorAll(\n \".search_field_clear, .js_filter_field_clear\"\n )\n key(\"alt+f\", function () {\n key.setScope(\"search\")\n search_fields.forEach((el) => el.focus({ focusVisible: true }))\n return false\n })\n bindedHotkeys.push(\"alt+f\")\n key(\"esc\", \"search\", function () {\n search_fields_clear.forEach((el) => el.click())\n search_fields.forEach((el) => el.blur())\n })\n bindedHotkeys.push(\"esc\")\n\n // Binds click events to buttons with hotkeys.\n //\n // Simply add a data-alchemy-hotkey attribute to your link.\n // If a hotkey is triggered by user, the click event of the element gets triggerd.\n //\n scope.querySelectorAll(\"[data-alchemy-hotkey]\").forEach(function (el) {\n const hotkey = el.dataset.alchemyHotkey\n key(hotkey, () => el.click())\n bindedHotkeys.push(hotkey)\n })\n}\n","/**\n * create a HTML element\n * @param {string} text\n * @returns {HTMLElement}\n */\nexport function createHtmlElement(text) {\n const element = document.createElement(\"template\")\n element.innerHTML = text\n return element.content.children[0]\n}\n\n/**\n * wrap element with wrappingElement\n * @param {HTMLElement} element\n * @param {HTMLElement} wrappingElement\n */\nexport function wrap(element, wrappingElement) {\n element.replaceWith(wrappingElement)\n wrappingElement.appendChild(element)\n}\n","import { createHtmlElement } from \"alchemy_admin/utils/dom_helpers\"\n\nexport default class Spinner {\n constructor(size, color = \"currentColor\") {\n this.size = size\n this.color = color\n this.spinner = undefined\n }\n\n /**\n * @returns {HTMLElement|undefined}\n */\n get el() {\n return this.spinner\n }\n /**\n * @param {HTMLElement|undefined} parent\n */\n spin(parent) {\n if (typeof parent === \"undefined\") {\n parent = document.body\n }\n this.spinner = createHtmlElement(\n ``\n )\n parent.append(this.spinner)\n return this\n }\n\n stop() {\n if (this.spinner) {\n this.spinner.remove()\n this.spinner = undefined\n }\n }\n}\n","import Hotkeys from \"alchemy_admin/hotkeys\"\nimport Spinner from \"alchemy_admin/spinner\"\n\n// Collection of all current dialog instances\nconst currentDialogs = []\n\nconst DEFAULTS = {\n header_height: 36,\n size: \"400x300\",\n padding: true,\n title: \"\",\n modal: true,\n overflow: \"visible\",\n ready: () => {},\n closed: () => {}\n}\n\nexport class Dialog {\n // Arguments:\n // - url: The url to load the content from via ajax\n // - options: A object holding options\n // - size: The maximum size of the Dialog\n // - title: The title of the Dialog\n constructor(url, options = {}) {\n this.url = url\n this.options = { ...DEFAULTS, ...options }\n this.$document = $(document)\n this.$window = $(window)\n this.$body = $(\"body\")\n const size = this.options.size.split(\"x\")\n this.width = parseInt(size[0], 10)\n this.height = parseInt(size[1], 10)\n this.build()\n this.resize()\n }\n\n // Opens the Dialog and loads the content via ajax.\n open() {\n this.dialog.trigger(\"Alchemy.DialogOpen\")\n this.bind_close_events()\n window.requestAnimationFrame(() => {\n this.dialog_container.addClass(\"open\")\n if (this.overlay != null) {\n return this.overlay.addClass(\"open\")\n }\n })\n this.$body.addClass(\"prevent-scrolling\")\n currentDialogs.push(this)\n this.load()\n }\n\n // Closes the Dialog and removes it from the DOM\n close() {\n this.dialog.trigger(\"DialogClose.Alchemy\")\n this.$document.off(\"keydown\")\n this.dialog_container.removeClass(\"open\")\n if (this.overlay != null) {\n this.overlay.removeClass(\"open\")\n }\n this.$document.on(\n \"webkitTransitionEnd transitionend oTransitionEnd\",\n () => {\n this.$document.off(\"webkitTransitionEnd transitionend oTransitionEnd\")\n this.dialog_container.remove()\n if (this.overlay != null) {\n this.overlay.remove()\n }\n this.$body.removeClass(\"prevent-scrolling\")\n currentDialogs.pop(this)\n if (this.options.closed != null) {\n return this.options.closed()\n }\n }\n )\n return true\n }\n\n // Loads the content via ajax and replaces the Dialog body with server response.\n load() {\n this.show_spinner()\n $.get(this.url, (data) => {\n this.replace(data)\n }).fail((xhr) => {\n this.show_error(xhr)\n })\n }\n\n // Reloads the Dialog content\n reload() {\n this.dialog_body.empty()\n this.load()\n }\n\n // Replaces the dialog body with given content and initializes it.\n replace(data) {\n this.remove_spinner()\n this.dialog_body.hide()\n this.dialog_body.html(data)\n this.init()\n this.dialog[0].dispatchEvent(\n new CustomEvent(\"DialogReady.Alchemy\", {\n bubbles: true,\n detail: {\n body: this.dialog_body[0]\n }\n })\n )\n if (this.options.ready != null) {\n this.options.ready(this.dialog_body)\n }\n this.dialog_body.show()\n }\n\n // Adds a spinner into Dialog body\n show_spinner() {\n this.spinner = new Spinner(\"medium\")\n this.spinner.spin(this.dialog_body[0])\n }\n\n // Removes the spinner from Dialog body\n remove_spinner() {\n this.spinner.stop()\n }\n\n // Initializes the Dialog body\n init() {\n Hotkeys(this.dialog_body)\n this.watch_remote_forms()\n }\n\n // Watches ajax requests inside of dialog body and replaces the content accordingly\n watch_remote_forms() {\n const $form = $('[data-remote=\"true\"]', this.dialog_body)\n\n $form.on(\"ajax:success\", (event) => {\n const xhr = event.detail[2]\n const content_type = xhr.getResponseHeader(\"Content-Type\")\n if (content_type.match(/javascript/)) {\n return\n } else {\n this.dialog_body.html(xhr.responseText)\n this.init()\n }\n })\n\n $form.on(\"ajax:error\", (event) => {\n const statusText = event.detail[1]\n const xhr = event.detail[2]\n this.show_error(xhr, statusText)\n })\n }\n\n // Displays an error message\n show_error(xhr, statusText) {\n if (xhr.status === 422) {\n this.dialog_body.html(xhr.responseText)\n this.init()\n return\n }\n\n const { error_body, error_header, error_type } = this.error_messages(\n xhr,\n statusText\n )\n\n const $errorDiv = $(`\n

${error_header}

\n

${error_body}

\n
`)\n\n this.dialog_body.html($errorDiv)\n }\n\n // Returns error message based on xhr status\n error_messages(xhr, statusText) {\n let error_body,\n error_header,\n error_type = \"warning\"\n\n switch (xhr.status) {\n case 0:\n error_header = \"The server does not respond.\"\n error_body = \"Please check server and try again.\"\n break\n case 403:\n error_header = \"You are not authorized!\"\n error_body = \"Please close this window.\"\n break\n default:\n error_type = \"error\"\n if (statusText) {\n error_header = statusText\n console.error(xhr.responseText)\n } else {\n error_header = `${xhr.statusText} (${xhr.status})`\n }\n error_body = \"Please check log and try again.\"\n }\n\n return { error_header, error_body, error_type }\n }\n\n // Binds close events on:\n // - Close button\n // - Overlay (if the Dialog is a modal)\n // - ESC Key\n bind_close_events() {\n this.close_button.on(\"click\", () => {\n this.close()\n })\n this.dialog_container.addClass(\"closable\").on(\"click\", (e) => {\n if (e.target !== this.dialog_container.get(0)) {\n return true\n }\n this.close()\n return false\n })\n this.$document.keydown((e) => {\n if (e.which === 27) {\n this.close()\n return false\n } else {\n return true\n }\n })\n }\n\n // Builds the html structure of the Dialog\n build() {\n this.dialog_container = $('
')\n this.dialog = $('
')\n this.dialog_body = $('
')\n this.dialog_header = $('
')\n this.dialog_title = $('
')\n this.close_button = $(\n ''\n )\n this.dialog_title.text(this.options.title)\n this.dialog_header.append(this.dialog_title)\n this.dialog_header.append(this.close_button)\n this.dialog.append(this.dialog_header)\n this.dialog.append(this.dialog_body)\n this.dialog_container.append(this.dialog)\n if (this.options.modal) {\n this.dialog.addClass(\"modal\")\n }\n if (this.options.padding) {\n this.dialog_body.addClass(\"padded\")\n }\n if (this.options.modal) {\n this.overlay = $('
')\n this.$body.append(this.overlay)\n }\n this.$body.append(this.dialog_container)\n }\n\n // Sets the correct size of the dialog\n // It normalizes the given size, so that it never acceeds the window size.\n resize() {\n const { width, height } = this.getSize()\n\n this.dialog.css({\n width: width,\n \"min-height\": height,\n overflow: this.options.overflow\n })\n\n if (this.options.overflow === \"hidden\") {\n this.dialog_body.css({\n height: height,\n overflow: \"auto\"\n })\n } else {\n this.dialog_body.css({\n \"min-height\": height,\n overflow: \"visible\"\n })\n }\n }\n\n getSize() {\n const padding = this.options.padding ? 16 : 0\n const doc_width = this.$window.width()\n const doc_height = this.$window.height()\n\n let width = this.width\n let height = this.height\n\n if (width >= doc_width) {\n width = doc_width - padding\n }\n\n if (height >= doc_height) {\n height = doc_height - padding - DEFAULTS.header_height\n }\n\n return { width, height }\n }\n}\n\n// Gets the last dialog instantiated, which is the current one.\nexport function currentDialog() {\n const { length } = currentDialogs\n if (length === 0) {\n return\n }\n return currentDialogs[length - 1]\n}\n\n// Utility function to close the current Dialog\n//\n// You can pass a callback function, that gets triggered after the Dialog gets closed.\n//\nexport function closeCurrentDialog(callback) {\n const dialog = currentDialog()\n if (dialog != null) {\n dialog.options.closed = callback\n return dialog.close()\n }\n}\n\n// Utility function to open a new Dialog\nexport function openDialog(url, options) {\n if (!url) {\n throw \"No url given! Please provide an url.\"\n }\n const dialog = new Dialog(url, options)\n dialog.open()\n}\n","import { createHtmlElement } from \"alchemy_admin/utils/dom_helpers\"\nimport { translate } from \"alchemy_admin/i18n\"\n\nconst getDefaults = () => ({\n // The default size of the dialog\n size: \"300x100\",\n title: translate(\"Please confirm\"),\n ok_label: translate(\"Yes\"),\n cancel_label: translate(\"No\"),\n on_ok() {}\n})\n\nclass ConfirmDialog {\n constructor(message, options = {}) {\n this.message = message\n this.options = { ...getDefaults(), ...options }\n this.#build()\n this.#bindEvents()\n }\n\n open() {\n requestAnimationFrame(() => {\n this.dialog.show()\n })\n }\n\n #build() {\n const width = this.options.size.split(\"x\")[0]\n this.dialog = createHtmlElement(`\n \n ${this.message}\n \n \n \n `)\n document.body.append(this.dialog)\n }\n\n #bindEvents() {\n this.cancelButton.addEventListener(\"click\", (evt) => {\n evt.preventDefault()\n this.options.on_cancel()\n this.dialog.hide()\n })\n this.okButton.addEventListener(\"click\", (evt) => {\n evt.preventDefault()\n this.options.on_ok()\n this.dialog.hide()\n })\n // Prevent the dialog from closing when the user clicks on the overlay\n this.dialog.addEventListener(\"sl-request-close\", (event) => {\n if (event.detail.source === \"overlay\") {\n this.options.on_cancel()\n event.preventDefault()\n }\n })\n // Remove the dialog from the DOM after it has been hidden\n this.dialog.addEventListener(\"sl-after-hide\", () => {\n this.dialog.remove()\n })\n }\n\n get cancelButton() {\n return this.dialog.querySelector(\"button[type=reset]\")\n }\n\n get okButton() {\n return this.dialog.querySelector(\"button[type=submit]\")\n }\n}\n\n/* Opens a confirm dialog\n *\n * @param {string} message - The message that will be displayed to the user\n * @param {Object} [options={}] - Configuration options for the dialog\n * @param {string} [options.title=\"Please confirm\"] - The title of the overlay window\n * @param {string} [options.cancel_label=\"No\"] - The label of the cancel button\n * @param {string} [options.ok_label=\"Yes\"] - The label of the ok button\n *\n * @returns {Promise} A promise that resolves to true when the OK button is clicked and\n * resolves to false when the cancel button is clicked. Works as confirm dialog replacement\n * for Turbo.confirm.\n */\nexport function openConfirmDialog(message, options = {}) {\n return new Promise((resolve) => {\n const dialog = new ConfirmDialog(message, {\n ...options,\n on_ok() {\n resolve(true)\n },\n on_cancel() {\n resolve(false)\n }\n })\n dialog.open()\n })\n}\n","/**\n * To show the \"Please wait\" overlay.\n * Pass false to hide it.\n * @param {boolean} show\n */\nexport default function pleaseWaitOverlay(show = true) {\n document.querySelector(\"alchemy-overlay\").show = !!show\n}\n","import { openConfirmDialog } from \"alchemy_admin/confirm_dialog\"\nimport { translate } from \"alchemy_admin/i18n\"\nimport pleaseWaitOverlay from \"alchemy_admin/please_wait_overlay\"\n\nfunction checkPageDirtyness(element) {\n let callback = () => {}\n\n if ($(element).is(\"form\")) {\n callback = function () {\n const $form = $(\n `
`\n )\n $form.append($(element).find(\"input\"))\n $form.appendTo(\"body\")\n\n pleaseWaitOverlay()\n $form.trigger(\"submit\")\n }\n } else if ($(element).is(\"a\")) {\n callback = () => Turbo.visit(element.pathname)\n }\n\n const isPageDirty =\n document.querySelectorAll(\"alchemy-element-editor.dirty\").length > 0\n\n if (isPageDirty) {\n openConfirmDialog(translate(\"page_dirty_notice\"), {\n title: translate(\"warning\"),\n ok_label: translate(\"ok\"),\n cancel_label: translate(\"cancel\")\n }).then((proceed) => {\n if (proceed) {\n window.onbeforeunload = void 0\n callback()\n }\n })\n return false\n }\n return true\n}\n\nfunction PageLeaveObserver() {\n document.querySelectorAll(\"#main_navi a\").forEach((element) => {\n element.addEventListener(\"click\", (event) => {\n if (!checkPageDirtyness(event.currentTarget)) {\n event.preventDefault()\n }\n })\n })\n}\n\nexport default {\n checkPageDirtyness,\n PageLeaveObserver\n}\n","// Creates a fixed element tab.\nexport function createTab(element_id, label) {\n const fixed_elements = document.getElementById(\"fixed-elements\")\n const panel_name = `fixed-element-${element_id}`\n\n const tab = `${label}`\n const panel = ``\n\n fixed_elements.innerHTML += tab + panel\n\n window.requestAnimationFrame(function () {\n fixed_elements.show(panel_name)\n })\n}\n\nexport function removeTab(element_id) {\n const fixed_elements = document.getElementById(\"fixed-elements\")\n const panel_name = `fixed-element-${element_id}`\n\n fixed_elements.querySelector(`sl-tab[panel=\"${panel_name}\"]`).remove()\n fixed_elements.querySelector(`sl-tab-panel[name=\"${panel_name}\"]`).remove()\n\n fixed_elements.show(\"main-content-elements\")\n}\n","import { createHtmlElement } from \"alchemy_admin/utils/dom_helpers\"\n\nfunction build(message, flashType) {\n const flashNotices = document.getElementById(\"flash_notices\")\n const flashMessage = createHtmlElement(`\n \n ${message}\n \n `)\n flashNotices.append(flashMessage)\n}\n\nexport function growl(message, style = \"notice\") {\n build(message, style)\n}\n","import { translate } from \"alchemy_admin/i18n\"\nimport { Dialog } from \"alchemy_admin/dialog\"\n\n// Matches a URL fragment (#anchor) at the end of a string.\n// Covers RFC 3986 unreserved characters (ALPHA, DIGIT, \"-\", \".\", \"_\", \"~\")\n// which are the characters valid in URL fragments and common in DOM element IDs.\nconst ANCHOR_REGEX = /#[\\w.~-]+$/\n\n// Represents the link Dialog that appears, if a user clicks the link buttons\n// in TinyMCE or on an Ingredient that has links enabled (e.g. Picture)\n//\nexport class LinkDialog extends Dialog {\n #onCreateLink\n\n constructor(link) {\n const url = new URL(Alchemy.routes.link_admin_pages_path, window.location)\n const parameterMapping = {\n url: link.url,\n selected_tab: link.type,\n link_title: link.title,\n link_target: link.target\n }\n\n // searchParams.set would also add undefined values\n Object.keys(parameterMapping).forEach((key) => {\n if (parameterMapping[key]) {\n url.searchParams.set(key, parameterMapping[key])\n }\n })\n\n super(url.href, {\n size: \"600x320\",\n title: translate(\"Link\")\n })\n }\n\n /**\n * Called from Dialog class after the url was loaded\n */\n replace(data) {\n // let Dialog class handle the content replacement\n super.replace(data)\n this.#attachEvents()\n }\n\n /**\n * make the open method a promise\n * maybe in a future version the whole Dialog will respond with a promise result if the dialog is closing\n * @returns {Promise}\n */\n open() {\n super.open()\n return new Promise((resolve) => (this.#onCreateLink = resolve))\n }\n\n /**\n * Attaches click events to forms in the link dialog.\n */\n #attachEvents() {\n // enable the dom selection in internal link tab\n const internalForm = document.querySelector(\n '[data-link-form-type=\"internal\"]'\n )\n const attachmentSelect = document.querySelector(\n '[data-link-form-type=\"file\"] alchemy-attachment-select'\n )\n\n internalForm.addEventListener(\"Alchemy.RemoteSelect.Change\", (e) => {\n this.#updatePage(e.detail.added)\n })\n\n attachmentSelect.addEventListener(\"Alchemy.RemoteSelect.Change\", (e) => {\n const attachment = e.detail.added\n document.getElementById(\"file_link\").value = attachment\n ? attachment.url\n : \"\"\n })\n\n document.querySelectorAll(\"[data-link-form-type]\").forEach((form) => {\n form.addEventListener(\"submit\", (e) => {\n e.preventDefault()\n this.#submitForm(e.target.dataset.linkFormType)\n })\n })\n }\n\n /**\n * update page select and set anchor select\n * @param page\n */\n #updatePage(page = null) {\n const internalLink = document.getElementById(\"internal_link\")\n const domIdSelect = document.querySelector(\n '[data-link-form-type=\"internal\"] alchemy-dom-id-api-select'\n )\n\n internalLink.value = page ? page.url_path : \"\"\n domIdSelect.page = page ? page.id : undefined\n }\n\n /**\n * submit the form itself\n * @param linkType\n */\n #submitForm(linkType) {\n const elementAnchor = document.getElementById(\"element_anchor\")\n let url = document.getElementById(`${linkType}_link`).value\n\n if (linkType === \"internal\" && elementAnchor.value !== \"\") {\n // remove possible fragments on the url and attach the fragment (which contains the #)\n url = url.replace(ANCHOR_REGEX, \"\") + elementAnchor.value\n } else if (linkType === \"external\" && !url.match(Alchemy.link_url_regexp)) {\n // show validation error and prevent link creation\n this.#showValidationError()\n return\n }\n\n // Create the link\n this.#onCreateLink({\n url: url.trim(),\n title: document.getElementById(`${linkType}_link_title`).value,\n target: document.getElementById(`${linkType}_link_target`)?.value,\n type: linkType\n })\n this.close()\n }\n\n /**\n * Shows validation errors\n */\n #showValidationError() {\n const errors = document.getElementById(\"errors\")\n errors.querySelector(\"ul\").innerHTML =\n `
  • ${Alchemy.t(\"url_validation_failed\")}
  • `\n errors.style.display = \"block\"\n }\n}\n","import { growl } from \"alchemy_admin/growler\"\nimport { translate } from \"alchemy_admin/i18n\"\n\nclass PreviewWindow extends HTMLIFrameElement {\n #afterLoad\n #reloadIcon\n #loadTimeout\n #previewReadyHandler\n\n constructor() {\n super()\n this.addEventListener(\"load\", this)\n this.#previewReadyHandler = this.#handlePreviewReadyMessage.bind(this)\n }\n\n handleEvent(evt) {\n if (evt.type === \"load\") {\n this.#clearLoadTimeout()\n this.#stopSpinner()\n this.#afterLoad?.call(this, evt)\n }\n }\n\n #handlePreviewReadyMessage(event) {\n if (event.data.message === \"Alchemy.previewReady\") {\n this.#clearLoadTimeout()\n this.#stopSpinner()\n this.#afterLoad?.call(this, event)\n }\n }\n\n connectedCallback() {\n let url = this.url\n\n this.#attachEvents()\n window.addEventListener(\"message\", this.#previewReadyHandler)\n\n if (window.localStorage.getItem(\"alchemy-preview-url\")) {\n url = window.localStorage.getItem(\"alchemy-preview-url\")\n this.previewUrlSelect.value = url\n }\n\n this.refresh(url)\n }\n\n disconnectedCallback() {\n key.unbind(\"alt+r\")\n window.removeEventListener(\"message\", this.#previewReadyHandler)\n }\n\n postMessage(data) {\n this.contentWindow.postMessage(data, \"*\")\n }\n\n resize(width) {\n this.style.width = `${width}px`\n }\n\n refresh(url) {\n this.#startSpinner()\n\n if (url) {\n this.src = url\n } else {\n this.src = this.url\n }\n\n // Set 5s timeout as fallback - if iframe doesn't load, stop spinner anyway\n this.#clearLoadTimeout()\n this.#loadTimeout = setTimeout(() => {\n this.#stopSpinner()\n growl(translate(\"Preview failed to load\"), \"warning\")\n }, 5000)\n\n return new Promise((resolve) => {\n this.#afterLoad = resolve\n })\n }\n\n set isDragged(dragged) {\n this.style.transitionProperty = dragged ? \"none\" : null\n this.style.pointerEvents = dragged ? \"none\" : null\n }\n\n #attachEvents() {\n this.reloadButton?.addEventListener(\"click\", (evt) => {\n evt.preventDefault()\n this.refresh()\n })\n\n key(\"alt+r\", () => this.refresh())\n\n this.sizeSelect.addEventListener(\"change\", (evt) => {\n const select = evt.target\n const width = select.value\n\n if (width === \"\") {\n this.style.width = null\n } else {\n this.resize(width)\n }\n })\n\n this.previewUrlSelect?.addEventListener(\"change\", (evt) => {\n const url = evt.target.value\n window.localStorage.setItem(\"alchemy-preview-url\", url)\n this.refresh(url)\n })\n }\n\n #startSpinner() {\n // Only save the reload icon if we're not already showing a spinner\n if (!this.reloadButton.innerHTML.includes(\"alchemy-spinner\")) {\n this.#reloadIcon = this.reloadButton.innerHTML\n }\n this.reloadButton.innerHTML = ``\n }\n\n #stopSpinner() {\n this.reloadButton.innerHTML = this.#reloadIcon\n }\n\n #clearLoadTimeout() {\n if (this.#loadTimeout) {\n clearTimeout(this.#loadTimeout)\n this.#loadTimeout = null\n }\n }\n\n get url() {\n return this.getAttribute(\"url\")\n }\n\n get sizeSelect() {\n return document.querySelector(\"select#preview_size\")\n }\n\n get previewUrlSelect() {\n return document.querySelector(\"select#preview_url\")\n }\n\n get reloadButton() {\n return document.querySelector(\"#reload_preview_button\")\n }\n}\n\ncustomElements.define(\"alchemy-preview-window\", PreviewWindow, {\n extends: \"iframe\"\n})\n\nexport function reloadPreview() {\n const previewWindow = document.getElementById(\"alchemy_preview_window\")\n previewWindow.refresh()\n}\n","export default class IngredientAnchorLink {\n static updateIcon(ingredientId, active = false) {\n const ingredientEditor = document.querySelector(\n `[data-ingredient-id=\"${ingredientId}\"]`\n )\n if (ingredientEditor) {\n const icon = ingredientEditor.querySelector(\n \".edit-ingredient-anchor-link alchemy-icon\"\n )\n icon.setAttribute(\"icon-style\", active ? \"fill\" : \"line\")\n }\n }\n}\n","import { reloadPreview } from \"alchemy_admin/components/preview_window\"\nimport { removeTab } from \"alchemy_admin/fixed_elements\"\nimport { closeCurrentDialog } from \"alchemy_admin/dialog\"\nimport IngredientAnchorLink from \"alchemy_admin/ingredient_anchor_link\"\nimport pleaseWaitOverlay from \"alchemy_admin/please_wait_overlay\"\n\nclass Action extends HTMLElement {\n constructor() {\n super()\n\n // map action names with Javascript functions\n this.actions = {\n // add a intermediate closeCurrentDialog - action\n // this will be gone, if all dialogs are working with a promise and\n // we don't have to implicitly close the dialog\n closeCurrentDialog,\n reloadPreview,\n removeFixedElement: removeTab,\n updateAnchorIcon: IngredientAnchorLink.updateIcon,\n hidePleaseWaitOverlay() {\n pleaseWaitOverlay(false)\n }\n }\n }\n\n connectedCallback() {\n const func = this.actions[this.name]\n\n if (func) {\n func(...this.params)\n } else {\n console.error(`Unknown Alchemy action: ${this.name}`)\n }\n\n this.remove()\n }\n\n get name() {\n return this.getAttribute(\"name\")\n }\n\n get params() {\n if (this.hasAttribute(\"params\")) {\n return JSON.parse(this.getAttribute(\"params\"))\n }\n return []\n }\n}\n\ncustomElements.define(\"alchemy-action\", Action)\n","import { toCamelCase } from \"alchemy_admin/utils/string_conversions\"\n\nexport class AlchemyHTMLElement extends HTMLElement {\n static properties = {}\n\n /**\n * create the list of observed attributes\n * this function is a requirement for the `attributeChangedCallback` - method\n * @returns {string[]}\n * @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Components#reference\n */\n static get observedAttributes() {\n return Object.keys(this.properties)\n }\n\n constructor(options = {}) {\n super()\n\n this.options = options\n this.changeComponent = true\n this.initialContent = this.innerHTML // store the inner content of the component\n }\n\n /**\n * run when the component will be initialized by the Browser\n * this is a default function\n * @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Components#reference\n */\n async connectedCallback() {\n // parse the properties object and register property with the default values\n Object.keys(this.constructor.properties).forEach((name) => {\n // if the options was given via the constructor, they should be prefer (e.g. new ({title: \"Foo\"}))\n this[name] =\n this.options[name] ?? this.constructor.properties[name].default\n })\n\n // then process the attributes\n this.getAttributeNames().forEach((name) => this._updateFromAttribute(name))\n\n // render the component\n this._updateComponent()\n await this.connected()\n }\n\n /**\n * disconnected callback if the component is removed from the DOM\n * this is currently only a Proxy to the disconnected - callback to use the same callback structure\n * as for the connected - callback\n * @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Components#reference\n */\n disconnectedCallback() {\n this.disconnected()\n }\n\n /**\n * triggered by the browser, if one of the observed attributes is changing\n * @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Components#reference\n */\n attributeChangedCallback(name) {\n this._updateFromAttribute(name)\n this._updateComponent()\n }\n\n /**\n * a connected method to make it easier to overwrite the connection callback\n */\n async connected() {}\n\n /**\n * a disconnected method to make it easier to overwrite the disconnection callback\n */\n disconnected() {}\n\n /**\n * empty method container to allow the child component to put the rendered string into this method\n * @returns {String}\n */\n render() {\n return this.initialContent\n }\n\n /**\n * after render callback\n * the function will be triggered after the DOM was updated\n */\n afterRender() {}\n\n /**\n * Dispatches a custom event with given name\n * @param {string} name The name of the custom event\n * @param {object} detail Optional event details\n */\n dispatchCustomEvent(name, detail = {}) {\n const event = new CustomEvent(`Alchemy.${name}`, { bubbles: true, detail })\n this.dispatchEvent(event)\n }\n\n /**\n * (re)render the component content inside the component container\n * @private\n */\n _updateComponent() {\n if (this.changeComponent) {\n this.innerHTML = this.render()\n this.changeComponent = false\n this.afterRender()\n }\n }\n\n /**\n * update the value from the given attribute\n *\n * @param {string} name\n * @private\n */\n _updateFromAttribute(name) {\n const attributeValue = this.getAttribute(name)\n const propertyName = toCamelCase(name)\n const isBooleanValue =\n attributeValue.length === 0 || attributeValue === \"true\"\n\n const value = isBooleanValue ? true : attributeValue\n\n if (this[propertyName] !== value) {\n this[propertyName] = value\n this.changeComponent = true\n }\n }\n}\n","/**\n * convert dashes and underscore strings into camelCase strings\n * @param {string} str\n * @returns {string}\n */\nexport function toCamelCase(str) {\n return str\n .split(/-|_/)\n .reduce((a, b) => a + b.charAt(0).toUpperCase() + b.slice(1))\n}\n","import { AlchemyHTMLElement } from \"alchemy_admin/components/alchemy_html_element\"\nimport { setupSelectLocale } from \"alchemy_admin/i18n\"\n\nexport function hightlightTerm(name, term) {\n return name.replace(new RegExp(term, \"gi\"), (match) => `${match}`)\n}\n\nexport class RemoteSelect extends AlchemyHTMLElement {\n static properties = {\n allowClear: { default: false },\n selection: { default: undefined },\n placeholder: { default: \"\" },\n queryParams: { default: \"{}\" },\n url: { default: \"\" }\n }\n\n async connected() {\n await setupSelectLocale()\n\n this.input.classList.add(\"alchemy_selectbox\")\n\n $(this.input)\n .select2(this.select2Config)\n .on(\"select2-open\", (evt) => {\n this.onOpen(evt)\n })\n .on(\"change\", (evt) => {\n this.onChange(evt)\n })\n }\n\n /**\n * Optional on change handler called by Select2.\n * @param {Event} event\n */\n onChange(event) {\n this.dispatchCustomEvent(\"RemoteSelect.Change\", {\n removed: event.removed,\n added: event.added\n })\n }\n\n /**\n * Optional on open handler called by Select2.\n * @param {Event} event\n */\n onOpen(event) {\n // add focus to the search input. Select2 is handling the focus on the first opening,\n // but it does not work the second time. One process in select2 is \"stealing\" the focus\n // if the command is not delayed. It is an intermediate solution until we are going to\n // move away from Select2\n setTimeout(() => {\n document.querySelector(\"#select2-drop .select2-input\").focus()\n }, 100)\n }\n\n get input() {\n return this.getElementsByTagName(\"input\")[0]\n }\n\n get select2Config() {\n return {\n placeholder: this.placeholder,\n allowClear: this.allowClear,\n initSelection: (_$el, callback) => {\n if (this.selection) {\n callback(JSON.parse(this.selection))\n }\n },\n ajax: this.ajaxConfig,\n formatSelection: (item) => this._renderResult(item),\n formatResult: (item, _el, query) =>\n this._renderListEntry(item, query.term)\n }\n }\n\n /**\n * Ajax configuration for Select2\n * @returns {object}\n */\n get ajaxConfig() {\n return {\n url: this.url,\n datatype: \"json\",\n quietMillis: 300,\n data: (term, page) => this._searchQuery(term, page),\n results: (response) => this._parseResponse(response)\n }\n }\n\n /**\n * Search query send to server from select2\n * @param {string} term\n * @param {number} page\n * @returns {object}\n * @private\n */\n _searchQuery(term, page) {\n return {\n q: {\n name_cont: term,\n ...JSON.parse(this.queryParams)\n },\n page: page\n }\n }\n\n /**\n * Parses server response into select2 results object\n * @param {object} response\n * @returns {object}\n * @private\n */\n _parseResponse(response) {\n const meta = response.meta\n return {\n results: response.data,\n more: meta.page * meta.per_page < meta.total_count\n }\n }\n\n /**\n * result which is visible if a page was selected\n * @param {object} item\n * @returns {string}\n * @private\n */\n _renderResult() {\n throw new Error(\n \"You need to define a _renderResult function on your sub class!\"\n )\n }\n\n /**\n * html template for each list entry\n * @param {object} item\n * @param {string} term\n * @returns {string}\n * @private\n */\n _renderListEntry() {\n throw new Error(\n \"You need to define a _renderListEntry function on your sub class!\"\n )\n }\n\n /**\n * hightlighted search term\n * @param {string} name\n * @param {string} term\n * @returns {string}\n * @private\n */\n _hightlightTerm(name, term) {\n return hightlightTerm(name, term)\n }\n}\n","import { RemoteSelect } from \"alchemy_admin/components/remote_select\"\n\nclass AttachmentSelect extends RemoteSelect {\n _renderResult(item) {\n return this._renderListEntry(item)\n }\n\n /**\n * html template for each list entry\n * @param {object} page\n * @param {string} term\n * @returns {string}\n * @private\n */\n _renderListEntry(attachment, term) {\n return `\n
    \n \n ${this._hightlightTerm(attachment.name, term)}\n
    \n `\n }\n}\n\ncustomElements.define(\"alchemy-attachment-select\", AttachmentSelect)\n","// Dispatch a submit event on change of input or select elements\n// contained in a form, so that Turbo can submit the form.\nclass AutoSubmit extends HTMLElement {\n connectedCallback() {\n // Still using jQuery here, because select2 does not emit\n // the event from the original select element.\n $(this).on(\"change\", function (event) {\n // We need to dispatch a submit event, so that Turbo that listens\n // to it submits the search form us.\n const submitEvent = new Event(\"submit\", {\n bubbles: true,\n cancelable: true\n })\n event.target.form.dispatchEvent(submitEvent)\n return false\n })\n }\n}\n\ncustomElements.define(\"alchemy-auto-submit\", AutoSubmit)\n","import Spinner from \"alchemy_admin/spinner\"\n\nclass Button extends HTMLButtonElement {\n connectedCallback() {\n if (this.form) {\n this.form.addEventListener(\"submit\", this)\n\n if (this.form.dataset.remote == \"true\") {\n this.form.addEventListener(\"ajax:complete\", this)\n }\n\n this.form.addEventListener(\"turbo:submit-end\", this)\n } else {\n console.warn(\"No form for button found!\", this)\n }\n }\n\n handleEvent(event) {\n switch (event.type) {\n case \"submit\":\n const isDisabled = this.getAttribute(\"disabled\") === \"disabled\"\n\n if (isDisabled) {\n event.preventDefault()\n event.stopPropagation()\n } else {\n this.disable()\n }\n break\n case \"ajax:complete\":\n case \"turbo:submit-end\":\n this.enable()\n break\n }\n }\n\n disable() {\n const spinner = new Spinner(\"small\")\n const rect = this.getBoundingClientRect()\n\n this.dataset.initialButtonText = this.innerHTML\n this.setAttribute(\"disabled\", \"disabled\")\n this.setAttribute(\"tabindex\", \"-1\")\n this.classList.add(\"disabled\")\n this.style.width = `${rect.width}px`\n this.style.height = `${rect.height}px`\n this.innerHTML = \" \"\n\n spinner.spin(this)\n }\n\n enable() {\n this.classList.remove(\"disabled\")\n this.removeAttribute(\"disabled\")\n this.removeAttribute(\"tabindex\")\n this.style.width = null\n this.style.height = null\n this.innerHTML = this.dataset.initialButtonText\n }\n}\n\ncustomElements.define(\"alchemy-button\", Button, { extends: \"button\" })\n","/**\n * Show the character counter below input fields and textareas\n */\nimport { AlchemyHTMLElement } from \"alchemy_admin/components/alchemy_html_element\"\nimport { translate } from \"alchemy_admin/i18n\"\n\nclass CharCounter extends AlchemyHTMLElement {\n static properties = {\n maxChars: { default: 60 }\n }\n connected() {\n this.translation = translate(\"allowed_chars\", this.maxChars)\n this.formField = this.getFormField()\n\n if (this.formField) {\n this.createDisplayElement()\n this.countCharacters()\n this.formField.addEventListener(\"keyup\", () => this.countCharacters()) // add arrow function to get a implicit this - binding\n }\n }\n\n getFormField() {\n const formFields = this.querySelectorAll(\"input, textarea\")\n return formFields.length > 0 ? formFields[0] : undefined\n }\n\n createDisplayElement() {\n this.display = document.createElement(\"small\")\n this.display.className = \"alchemy-char-counter\"\n this.formField.after(this.display)\n }\n\n countCharacters() {\n const charLength = this.formField.value.length\n this.display.textContent = `${charLength} ${this.translation}`\n this.display.classList.toggle(\"too-long\", charLength > this.maxChars)\n }\n}\n\ncustomElements.define(\"alchemy-char-counter\", CharCounter)\n","import \"clipboard\"\nimport { growl } from \"alchemy_admin/growler\"\n\nclass ClipboardButton extends HTMLElement {\n constructor() {\n super()\n\n this.innerHTML = `\n \n `\n\n this.clipboard = new ClipboardJS(this, {\n text: () => {\n return this.getAttribute(\"content\")\n }\n })\n\n this.clipboard.on(\"success\", () => {\n growl(this.getAttribute(\"success-text\"))\n })\n }\n\n disconnectedCallback() {\n this.clipboard.destroy()\n }\n}\n\ncustomElements.define(\"alchemy-clipboard-button\", ClipboardButton)\n","const formatItem = (object) => {\n const optionEl = object.element[0]\n const swatch = optionEl.dataset.swatch || optionEl.value\n const customColor = optionEl.value === \"custom_color\"\n const colorIndicator = customColor\n ? ``\n : ``\n\n return `\n
    \n ${colorIndicator}\n ${object.text}\n
    `\n}\n\nclass ColorSelect extends HTMLElement {\n connectedCallback() {\n if (this.select) {\n this.#initializeSelect2()\n $(this.select).on(\"change\", (event) =>\n this.#toggleColorPicker(event.val === \"custom_color\")\n )\n } else {\n this.colorInput?.addEventListener(\"input\", this)\n this.textInput?.addEventListener(\"input\", this)\n this.#toggleColorPicker(true)\n }\n }\n\n handleEvent(event) {\n switch (event.target) {\n case this.colorInput:\n this.textInput.value = this.colorInput.value\n break\n case this.textInput:\n this.colorInput.value = this.textInput.value\n break\n }\n }\n\n disconnectedCallback() {\n this.colorInput?.removeEventListener(\"input\", this)\n this.textInput?.removeEventListener(\"input\", this)\n }\n\n #initializeSelect2() {\n this.select.classList.add(\"alchemy_selectbox\")\n const options = {\n minimumResultsForSearch: 10,\n formatResult: formatItem,\n formatSelection: formatItem\n }\n $(this.select).select2(options)\n }\n\n #toggleColorPicker(enabled = true) {\n this.colorInput.disabled = !enabled\n }\n\n get colorInput() {\n return this.querySelector(\"input[type='color']\")\n }\n\n get textInput() {\n return this.querySelector(\"input[type='text']\")\n }\n\n get select() {\n return this.querySelector(\"select\")\n }\n}\n\ncustomElements.define(\"alchemy-color-select\", ColorSelect)\n","import { AlchemyHTMLElement } from \"alchemy_admin/components/alchemy_html_element\"\nimport { translate, currentLocale } from \"alchemy_admin/i18n\"\nimport flatpickr from \"flatpickr\"\n\nconst locale = currentLocale()\n\nclass Datepicker extends AlchemyHTMLElement {\n static properties = {\n inputType: { default: \"date\" }\n }\n\n constructor() {\n super()\n this.flatpickr = undefined\n }\n\n // Load the locales for flatpickr before setting it up.\n async connected() {\n // English is the default locale for flatpickr, so we don't need to load it\n if (locale !== \"en\") {\n await import(`flatpickr/${locale}.js`)\n }\n\n this.flatpickr = flatpickr(this.inputField, this.flatpickrOptions)\n }\n\n disconnected() {\n this.flatpickr.destroy()\n }\n\n get flatpickrOptions() {\n const enableTime = /time/.test(this.inputType)\n const options = {\n // alchemy_i18n supports `zh_CN` etc., but flatpickr only has two-letter codes (`zh`)\n locale: locale.slice(0, 2),\n altInput: true,\n altFormat: translate(`formats.${this.inputType}`),\n altInputClass: \"flatpickr-input\",\n enableTime,\n noCalendar: this.inputType === \"time\",\n time_24hr: translate(\"formats.time_24hr\"),\n onValueUpdate(_selectedDates, _dateStr, instance) {\n instance.element\n .closest(\"alchemy-element-editor\")\n ?.setDirty(this.inputField)\n }\n }\n\n if (enableTime) {\n options.dateFormat = \"Z\"\n }\n\n return options\n }\n\n get inputField() {\n return this.querySelector(\"input\")\n }\n}\n\ncustomElements.define(\"alchemy-datepicker\", Datepicker)\n","import { Dialog } from \"alchemy_admin/dialog\"\n\nexport class DialogLink extends HTMLAnchorElement {\n constructor() {\n super()\n this.addEventListener(\"click\", this)\n }\n\n handleEvent(evt) {\n if (!this.disabled) {\n this.openDialog()\n }\n evt.preventDefault()\n }\n\n openDialog() {\n this.dialog = new Dialog(this.getAttribute(\"href\"), this.dialogOptions)\n this.dialog.open()\n }\n\n get dialogOptions() {\n const options = this.dataset.dialogOptions\n ? JSON.parse(this.dataset.dialogOptions)\n : {}\n return options\n }\n\n get disabled() {\n return this.classList.contains(\"disabled\")\n }\n}\n\ncustomElements.define(\"alchemy-dialog-link\", DialogLink, { extends: \"a\" })\n","const JSON_CONTENT_TYPE = \"application/json\"\nconst TURBO_STREAM_CONTENT_TYPE = \"text/vnd.turbo-stream.html\"\n\nfunction isGetRequest(method) {\n return method.toLowerCase() === \"get\"\n}\n\nfunction prepareURL(path, data, method) {\n const url = new URL(window.location.origin + path)\n\n if (data && isGetRequest(method)) {\n url.search = new URLSearchParams(data).toString()\n }\n\n return url.toString()\n}\n\nfunction prepareHeaders(accept) {\n return {\n \"Content-Type\": \"application/json; charset=utf-8\",\n Accept: accept,\n \"X-Requested-With\": \"XMLHttpRequest\",\n \"X-CSRF-Token\": getToken()\n }\n}\n\nfunction prepareOptions(method, data, accept) {\n const headers = prepareHeaders(accept)\n const options = { method, headers }\n\n if (data && !isGetRequest(method)) {\n options.body = JSON.stringify(data)\n }\n\n return options\n}\n\nexport function getToken() {\n const metaTag = document.querySelector('meta[name=\"csrf-token\"]')\n return metaTag.attributes.content.textContent\n}\n\nexport function get(url, params) {\n return ajax(\"GET\", url, params)\n}\n\nexport function patch(url, data, accept) {\n return ajax(\"PATCH\", url, data, accept)\n}\n\nexport function post(url, data, accept = JSON_CONTENT_TYPE) {\n return ajax(\"POST\", url, data, accept)\n}\n\nexport default async function ajax(\n method,\n path,\n data,\n accept = JSON_CONTENT_TYPE\n) {\n const response = await fetch(\n prepareURL(path, data, method),\n prepareOptions(method, data, accept)\n )\n const contentType = response.headers.get(\"content-type\")\n const isJson = contentType?.includes(JSON_CONTENT_TYPE)\n const isTurboStream = contentType?.includes(TURBO_STREAM_CONTENT_TYPE)\n\n let responseData = null\n if (isJson) {\n responseData = await response.json()\n } else if (isTurboStream) {\n responseData = await response.text()\n // Automatically render Turbo Stream if Turbo is available\n if (typeof Turbo !== \"undefined\") {\n Turbo.renderStreamMessage(responseData)\n }\n }\n\n if (response.ok) {\n return { data: responseData, status: response.status }\n } else {\n throw responseData || new Error(\"An error occurred during the transaction\")\n }\n}\n","import { get } from \"alchemy_admin/utils/ajax\"\nimport { translate } from \"alchemy_admin/i18n\"\n\nclass DomIdSelect extends HTMLElement {\n dataItem(hash) {\n return {\n id: `#${hash}`,\n text: `#${hash}`\n }\n }\n\n get selectElement() {\n return this.querySelector('select[is=\"alchemy-select\"]')\n }\n}\n\nclass DomIdApiSelect extends DomIdSelect {\n #pageId = undefined\n\n connectedCallback() {\n this.page = this.getAttribute(\"page\")\n }\n\n async #fetchDomIds() {\n const result = await get(Alchemy.routes.api_ingredients_path, {\n page_id: this.#pageId\n })\n const options = result.data.ingredients\n .filter((ingredient) => ingredient.data?.dom_id)\n .map((ingredient) => this.dataItem(ingredient.data.dom_id))\n const prompt =\n options.length > 0 ? translate(\"None\") : translate(\"No anchors found\")\n\n this.selectElement.setOptions(options, prompt)\n this.selectElement.enable()\n }\n\n #reset() {\n // wait a tick to initialize the alchemy-select\n requestAnimationFrame(() => {\n this.selectElement.disable()\n this.selectElement.setOptions([], translate(\"Select a page first\"))\n })\n }\n\n set page(pageId) {\n this.#pageId = pageId\n pageId ? this.#fetchDomIds() : this.#reset()\n }\n}\n\nclass DomIdPreviewSelect extends DomIdSelect {\n connectedCallback() {\n // wait a tick to let the browser initialize the inner select component\n requestAnimationFrame(() => {\n const frame = document.getElementById(\"alchemy_preview_window\")\n const elements = frame.contentDocument?.querySelectorAll(\"[id]\") || []\n if (elements.length > 0) {\n const options = Array.from(elements).map((element) => {\n return this.dataItem(element.id)\n })\n this.selectElement.setOptions(options, translate(\"None\"))\n }\n })\n }\n}\n\ncustomElements.define(\"alchemy-dom-id-api-select\", DomIdApiSelect)\ncustomElements.define(\"alchemy-dom-id-preview-select\", DomIdPreviewSelect)\n","export class PublishElementButton extends HTMLElement {\n #scheduleButtonVariant\n\n connectedCallback() {\n this.#scheduleButtonVariant = this.scheduleButton.getAttribute(\"variant\")\n this.publishButton.addEventListener(\"click\", this)\n this.dropdown.addEventListener(\"sl-show\", this)\n this.dropdown.addEventListener(\"sl-hide\", this)\n }\n\n disconnectedCallback() {\n this.publishButton.removeEventListener(\"click\", this)\n this.dropdown.removeEventListener(\"sl-show\", this)\n this.dropdown.removeEventListener(\"sl-hide\", this)\n }\n\n handleEvent(event) {\n switch (event.type) {\n case \"click\":\n this.publishButton.loading = true\n break\n case \"sl-show\":\n this.scheduleButton.setAttribute(\"variant\", \"primary\")\n break\n case \"sl-hide\":\n this.scheduleButton.setAttribute(\"variant\", this.#scheduleButtonVariant)\n break\n }\n }\n\n get publishButton() {\n return this.querySelector(\"sl-button[type='submit']\")\n }\n\n get dropdown() {\n return this.querySelector(\"sl-dropdown\")\n }\n\n get scheduleButton() {\n return this.querySelector(\"sl-button[slot='trigger']\")\n }\n}\n\ncustomElements.define(\"alchemy-publish-element-button\", PublishElementButton)\n","import ajax from \"alchemy_admin/utils/ajax\"\nimport { removeTab } from \"alchemy_admin/fixed_elements\"\nimport { growl } from \"alchemy_admin/growler\"\nimport { reloadPreview } from \"alchemy_admin/components/preview_window\"\nimport { openConfirmDialog } from \"alchemy_admin/confirm_dialog\"\nimport { dispatchPageDirtyEvent } from \"alchemy_admin/components/element_editor\"\n\nexport class DeleteElementButton extends HTMLElement {\n constructor() {\n super()\n this.button?.addEventListener(\"click\", this)\n }\n\n async handleEvent() {\n const confirmed = await openConfirmDialog(this.message)\n if (confirmed) {\n const response = await ajax(\"DELETE\", this.url)\n this.#removeElement(response.data)\n }\n }\n\n #removeElement(data) {\n const elementEditor = this.closest(\"alchemy-element-editor\")\n elementEditor.addEventListener(\"transitionend\", () => {\n if (elementEditor.fixed) {\n removeTab(elementEditor.elementId)\n }\n elementEditor.remove()\n })\n elementEditor.classList.add(\"dismiss\")\n growl(data.message)\n if (data.pageHasUnpublishedChanges) {\n dispatchPageDirtyEvent(data)\n }\n reloadPreview()\n }\n\n get url() {\n return this.getAttribute(\"href\")\n }\n\n get message() {\n return this.getAttribute(\"message\")\n }\n\n get button() {\n return this.querySelector(\"button\")\n }\n}\n\ncustomElements.define(\"alchemy-delete-element-button\", DeleteElementButton)\n","import IngredientAnchorLink from \"alchemy_admin/ingredient_anchor_link\"\nimport { post } from \"alchemy_admin/utils/ajax\"\nimport { createHtmlElement } from \"alchemy_admin/utils/dom_helpers\"\nimport { growl } from \"alchemy_admin/growler\"\n\nimport \"alchemy_admin/components/element_editor/publish_element_button\"\nimport \"alchemy_admin/components/element_editor/delete_element_button\"\n\nexport function dispatchPageDirtyEvent(data) {\n document.dispatchEvent(\n new CustomEvent(\"alchemy:page-dirty\", {\n detail: { tooltip: data.publishButtonTooltip }\n })\n )\n}\n\nexport class ElementEditor extends HTMLElement {\n constructor() {\n super()\n\n // Add event listeners\n this.addEventListener(\"click\", this)\n // Triggered by child elements\n this.addEventListener(\"alchemy:element-update-title\", this)\n // We use of @rails/ujs for Rails remote forms\n this.addEventListener(\"ajax:complete\", this)\n\n // Dirty observer still needs to be jQuery\n // in order to support select2.\n $(this.form).on(\"change\", this.onChange)\n\n this.header?.addEventListener(\"dblclick\", () => {\n this.toggle()\n })\n this.toggleButton?.addEventListener(\"click\", (evt) => {\n const elementEditor = evt.target.closest(\"alchemy-element-editor\")\n if (elementEditor === this) {\n this.toggle()\n }\n })\n }\n\n connectedCallback() {\n // The placeholder while be being dragged is empty.\n if (this.classList.contains(\"ui-sortable-placeholder\")) {\n return\n }\n\n // When newly created, focus the element and refresh the preview\n if (this.hasAttribute(\"created\")) {\n this.focusElement()\n this.previewWindow?.refresh().then(() => {\n this.focusElementPreview()\n })\n this.removeAttribute(\"created\")\n }\n }\n\n handleEvent(event) {\n switch (event.type) {\n case \"click\":\n const elementEditor = event.target.closest(\"alchemy-element-editor\")\n if (elementEditor === this) {\n this.onClickElement()\n }\n break\n case \"ajax:complete\":\n if (event.target === this.body) {\n const xhr = event.detail[0]\n event.stopPropagation()\n this.onSaveElement(xhr)\n }\n break\n case \"alchemy:element-update-title\":\n if (!this.hasEditors && event.target == this.firstChild) {\n this.setTitle(event.detail.title)\n }\n break\n }\n }\n\n onChange(event) {\n const target = event.target\n // SortableJS fires a native change event :/\n // and we do not want to set the element editor dirty\n // when this happens\n if (target.classList.contains(\"nested-elements\")) {\n return\n }\n this.closest(\"alchemy-element-editor\").setDirty(target)\n event.stopPropagation()\n return false\n }\n\n /**\n * Scrolls to and highlights element\n * Expands if collapsed\n * Also chooses the right fixed elements tab, if necessary.\n * Can be triggered through custom event 'FocusElementEditor.Alchemy'\n * Used by the elements on click events in the preview frame.\n */\n async focusElement() {\n // Select tab if necessary\n if (document.querySelector(\"#fixed-elements\")) {\n await this.selectTabForElement()\n }\n // Expand if necessary\n await this.expand()\n this.selectElement(true)\n }\n\n focusElementPreview() {\n this.previewWindow?.postMessage({\n message: \"Alchemy.focusElement\",\n element_id: this.elementId\n })\n }\n\n onClickElement() {\n this.selectElement()\n this.focusElementPreview()\n }\n\n /**\n * Sets the element to saved state\n * Updates title\n * JS event bubbling will also update the parents element quote.\n * Shows error messages if ingredient validations fail\n * @argument {XMLHttpRequest} xhr\n */\n onSaveElement(xhr) {\n const data = JSON.parse(xhr.responseText)\n // Reset errors that might be visible from last save attempt\n this.setClean()\n // If validation failed\n if (xhr.status === 422) {\n const warning = data.warning\n // Create error messages\n // Mark ingredients as failed\n data.ingredientsWithErrors.forEach((ingredient) => {\n const ingredientEditor = this.querySelector(\n `[data-ingredient-id=\"${ingredient.id}\"]`\n )\n const errorDisplay = createHtmlElement(\n `${ingredient.errorMessage}`\n )\n ingredientEditor?.appendChild(errorDisplay)\n ingredientEditor?.classList.add(\"validation_failed\")\n })\n // Show message\n growl(warning, \"warn\")\n this.elementErrors.classList.remove(\"hidden\")\n } else {\n growl(data.notice)\n this.previewWindow?.refresh().then(() => {\n this.focusElementPreview()\n })\n this.updateTitle(data.previewText)\n data.ingredientAnchors.forEach((anchor) => {\n IngredientAnchorLink.updateIcon(anchor.ingredientId, anchor.active)\n })\n if (data.pageHasUnpublishedChanges) {\n dispatchPageDirtyEvent(data)\n }\n }\n }\n\n /**\n * Smoothly scrolls to element\n */\n scrollToElement() {\n // The timeout gives the browser some time to calculate the position\n // of nested elements correctly\n setTimeout(() => {\n this.scrollIntoView({\n behavior: \"smooth\"\n })\n }, 50)\n }\n\n /**\n * Highlight element and optionally scroll into view\n * @param {boolean} scroll smoothly scroll element into view. Default (false)\n */\n selectElement(scroll = false) {\n document\n .querySelectorAll(\"alchemy-element-editor.selected\")\n .forEach((el) => {\n el.classList.remove(\"selected\")\n })\n window.requestAnimationFrame(() => {\n this.classList.add(\"selected\")\n })\n if (scroll) this.scrollToElement()\n }\n\n /**\n * Selects tab for given element\n * Resolves the promise if this is done.\n * @returns {Promise}\n */\n selectTabForElement() {\n return new Promise((resolve, reject) => {\n const tabs = document.querySelector(\"#fixed-elements\")\n const panel = this.closest(\"sl-tab-panel\")\n if (tabs && panel) {\n tabs.show(panel.getAttribute(\"name\"))\n resolve()\n } else {\n reject(new Error(\"No tabs present\"))\n }\n })\n }\n\n /**\n * Sets the element into clean (safed) state\n */\n setClean() {\n this.dirty = false\n window.onbeforeunload = null\n this.elementErrors.classList.add(\"hidden\")\n\n if (this.hasEditors) {\n this.body.querySelectorAll(\".ingredient-editor\").forEach((el) => {\n el.classList.remove(\"dirty\", \"validation_failed\")\n el.querySelectorAll(\"small.error\").forEach((e) => e.remove())\n })\n }\n }\n\n /**\n * Sets the element into dirty (unsafed) state\n * @param {HTMLElement} editor\n */\n setDirty(editor) {\n if (this.hasEditors) {\n this.dirty = true\n\n if (!window.onbeforeunload) {\n window.onbeforeunload = (event) => event.preventDefault()\n }\n\n editor?.closest(\".ingredient-editor\")?.classList.add(\"dirty\")\n }\n }\n\n /**\n * Sets the title quote\n * @param {string} title\n */\n setTitle(title) {\n const quote = this.querySelector(\".element-header .preview_text_quote\")\n quote.textContent = title\n }\n\n /**\n * Expands or collapses element editor\n * If the element is dirty (has unsaved changes) it displays a confirm first.\n */\n async toggle() {\n if (this.collapsed) {\n await this.expand()\n } else {\n await this.collapse()\n }\n }\n\n /**\n * Collapses the element editor and persists the state on the server\n * @returns {Promise}\n */\n collapse() {\n if (this.collapsed || this.compact || this.fixed) {\n return Promise.resolve(\"Element is already collapsed.\")\n }\n\n const spinner = new Alchemy.Spinner(\"small\")\n spinner.spin(this.toggleButton)\n this.toggleIcon?.classList?.add(\"hidden\")\n return post(Alchemy.routes.collapse_admin_element_path(this.elementId))\n .then((response) => {\n const data = response.data\n\n this.collapsed = true\n this.toggleButton?.setAttribute(\"title\", data.title)\n\n // Collapse all nested elements if necessarry\n if (data.nestedElementIds.length) {\n const selector = data.nestedElementIds\n .map((id) => `#element_${id}`)\n .join(\", \")\n this.querySelectorAll(selector).forEach((nestedElement) => {\n nestedElement.collapsed = true\n nestedElement.toggleButton?.setAttribute(\"title\", data.title)\n })\n }\n })\n .catch((error) => {\n growl(error.message, \"error\")\n console.error(error)\n })\n .finally(() => {\n this.toggleIcon?.classList?.remove(\"hidden\")\n spinner.stop()\n })\n }\n\n /**\n * Collapses the element editor and persists the state on the server\n * @* @returns {Promise}\n */\n expand() {\n if (this.expanded && !this.compact) {\n return Promise.resolve(\"Element is already expanded.\")\n }\n\n if (this.compact && this.parentElementEditor) {\n return this.parentElementEditor.expand()\n } else {\n const spinner = new Alchemy.Spinner(\"small\")\n spinner.spin(this.toggleButton)\n this.toggleIcon?.classList.add(\"hidden\")\n\n return new Promise((resolve, reject) => {\n post(Alchemy.routes.expand_admin_element_path(this.elementId))\n .then((response) => {\n const data = response.data\n\n // First expand all parent elements if necessary\n if (data.parentElementIds.length) {\n const selector = data.parentElementIds\n .map((id) => `#element_${id}`)\n .join(\", \")\n document.querySelectorAll(selector).forEach((parentElement) => {\n parentElement.collapsed = false\n parentElement.toggleButton?.setAttribute(\"title\", data.title)\n })\n }\n // Finally expand ourselve\n this.collapsed = false\n this.toggleButton?.setAttribute(\"title\", data.title)\n // Resolve the promise that scrolls to the element very last\n resolve()\n })\n .catch((error) => {\n growl(error.message, \"error\")\n console.error(error)\n reject(error)\n })\n .finally(() => {\n this.toggleIcon?.classList?.remove(\"hidden\")\n spinner.stop()\n })\n })\n }\n }\n\n /**\n * Updates the quote in the element header and dispatches event\n * to parent elements\n * @param {string} title\n */\n updateTitle(title) {\n this.setTitle(title)\n this.dispatchEvent(\n new CustomEvent(\"alchemy:element-update-title\", {\n bubbles: true,\n detail: { title }\n })\n )\n }\n\n /**\n * Sets element published or hidden\n * @param {boolean}\n */\n set published(isPublished) {\n if (isPublished) {\n this.classList.remove(\"element-hidden\")\n } else {\n this.classList.add(\"element-hidden\")\n }\n }\n\n /**\n * Is element published or hidden\n * @returns {boolean}\n */\n get published() {\n return !this.classList.contains(\"hidden\")\n }\n\n /**\n * @returns {boolean}\n */\n get compact() {\n return this.getAttribute(\"compact\") !== null\n }\n\n /**\n * @returns {boolean}\n */\n get fixed() {\n return this.getAttribute(\"fixed\") !== null\n }\n\n /**\n * @param {boolean} value\n */\n set collapsed(value) {\n this.classList.toggle(\"folded\", value)\n this.classList.toggle(\"expanded\", !value)\n this.toggleIcon &&\n (this.toggleIcon.name = value ? \"arrow-left-s\" : \"arrow-down-s\")\n }\n\n /**\n * @returns {boolean}\n */\n get collapsed() {\n return this.classList.contains(\"folded\")\n }\n\n /**\n * @returns {boolean}\n */\n get expanded() {\n return !this.collapsed\n }\n\n /**\n * Toggles the dirty class\n *\n * @param {boolean} value\n */\n set dirty(value) {\n this.classList.toggle(\"dirty\", value)\n }\n\n /**\n * Returns the dirty state of this element\n *\n * @returns {boolean}\n */\n get dirty() {\n return this.classList.contains(\"dirty\")\n }\n\n /**\n * Returns the element header\n *\n * @returns {HTMLElement|undefined}\n */\n get header() {\n return this.querySelector(`.element-header`)\n }\n\n /**\n * Returns the immediate body container of this element if present\n *\n * Makes sure it does not return a nested elements body\n * by scoping the selector to this elements id.\n *\n * @returns {HTMLElement|undefined}\n */\n get body() {\n return this.querySelector(this.bodySelector)\n }\n\n get bodySelector() {\n return `#${this.id} > .element-body`\n }\n\n /**\n * Returns the immediate footer container of this element if present\n *\n * Makes sure it does not return a nested elements footer\n * by scoping the selector to this elements id.\n *\n * @returns {HTMLElement|undefined}\n */\n get footer() {\n return this.querySelector(`#${this.id} > .element-footer`)\n }\n\n /**\n * The collapse/expand toggle button\n *\n * @returns {HTMLButtonElement|undefined}\n */\n get toggleButton() {\n return this.querySelector(\".element-toggle\")\n }\n\n /**\n * The collapse/expand toggle buttons icon\n *\n * @returns {HTMLElement|undefined}\n */\n get toggleIcon() {\n return this.toggleButton?.querySelector(\"alchemy-icon\")\n }\n\n /**\n * The validation messages list container\n *\n * @returns {HTMLElement}\n */\n get elementErrors() {\n return this.body.querySelector(\".element_errors\")\n }\n\n /**\n * The element database id\n *\n * @returns {string}\n */\n get elementId() {\n return this.dataset.elementId\n }\n\n /**\n * The element defintion name\n *\n * @returns {string}\n */\n get elementName() {\n return this.dataset.elementName\n }\n\n /**\n * Does this element have ingredient editor fields?\n *\n * @returns {boolean}\n */\n get hasEditors() {\n return !!this.body?.querySelector(\".element-ingredient-editors\")\n }\n\n /**\n * Does this element have nested elements?\n *\n * @returns {boolean}\n */\n get hasChildren() {\n return !!this.querySelector(\".nested-elements\")\n }\n\n /**\n * The first child element editor if present\n *\n * @returns {HTMLButtonElement|undefined}\n */\n get firstChild() {\n return this.querySelector(\"alchemy-element-editor\")\n }\n\n /**\n * The form element if present\n *\n * @returns {HTMLFormElement|undefined}\n */\n get form() {\n return this.querySelector(\"form.element-body\")\n }\n\n /**\n * The parent element editor if present\n *\n * @returns {ElementEditor|undefined}\n */\n get parentElementEditor() {\n return this.parentElement?.closest(\"alchemy-element-editor\")\n }\n\n get previewWindow() {\n return document.getElementById(\"alchemy_preview_window\")\n }\n}\n\ncustomElements.define(\"alchemy-element-editor\", ElementEditor)\n","import { hightlightTerm } from \"alchemy_admin/components/remote_select\"\n\nconst formatSelection = (option) => {\n return `\n
    \n ${option.icon}${option.text}\n
    \n `\n}\n\nconst formatItem = (icon, text, hint) => {\n const description = hint\n ? `
    ${hint}
    `\n : \"\"\n return `\n
    \n ${formatSelection({ icon, text })}\n ${description}\n
    \n `\n}\n\nclass ElementSelect extends HTMLElement {\n constructor() {\n super()\n }\n\n connectedCallback() {\n const results = this.options\n const options = {\n minimumResultsForSearch: 3,\n dropdownAutoWidth: true,\n data() {\n return { results }\n },\n formatResult: (option, _el, search) => {\n let text\n\n if (option.id === \"\") return option.text\n if (search.term !== \"\") {\n text = hightlightTerm(option.text, search.term)\n } else {\n text = option.text\n }\n\n return formatItem(option.icon, text, option.hint)\n },\n formatSelection,\n placeholder: this.placeholder\n }\n $(this.inputField).select2(options)\n }\n\n get options() {\n return JSON.parse(this.getAttribute(\"options\"))\n }\n\n get placeholder() {\n return this.getAttribute(\"placeholder\")\n }\n\n get inputField() {\n return this.querySelector(\"input\")\n }\n}\n\ncustomElements.define(\"alchemy-element-select\", ElementSelect)\n","import { ElementEditor } from \"alchemy_admin/components/element_editor\"\n\nclass ElementsWindow extends HTMLElement {\n #visible = true\n #turboFrame = null\n\n constructor() {\n super()\n this.#attachEvents()\n }\n\n connectedCallback() {\n this.toggleButton?.addEventListener(\"click\", (evt) => {\n evt.preventDefault()\n this.toggle()\n })\n if (window.location.hash) {\n this.focusElementEditor(window.location.hash)\n }\n this.resize()\n }\n\n collapseAllElements() {\n this.querySelectorAll(\n \"alchemy-element-editor:not([compact]):not([fixed])\"\n ).forEach((editor) => editor.collapse())\n }\n\n toggle() {\n this.#visible ? this.hide() : this.show()\n }\n\n show() {\n document.body.classList.add(\"elements-window-visible\")\n this.#visible = true\n this.toggleButton.closest(\"sl-tooltip\").content = Alchemy.t(\"Hide elements\")\n this.toggleButton\n .querySelector(\"alchemy-icon\")\n .setAttribute(\"name\", \"menu-unfold\")\n this.resize()\n }\n\n hide() {\n document.body.classList.remove(\"elements-window-visible\")\n document.body.style.removeProperty(\"--elements-window-width\")\n this.#visible = false\n this.toggleButton.closest(\"sl-tooltip\").content = Alchemy.t(\"Show elements\")\n this.toggleButton\n .querySelector(\"alchemy-icon\")\n .setAttribute(\"name\", \"menu-fold\")\n }\n\n resize(width) {\n if (width === undefined) {\n width = this.widthFromCookie\n }\n\n if (width) {\n document.body.style.setProperty(\"--elements-window-width\", `${width}px`)\n document.cookie = `alchemy-elements-window-width=${width}; SameSite=Lax; Path=/;`\n }\n }\n\n // Focus element editor and element in preview if URL contains hash to element editor.\n // The link is coming from the assignment view when showing assigned files or pictures.\n focusElementEditor(dom_id) {\n const el = document.querySelector(dom_id)\n\n if (el instanceof ElementEditor) {\n el.focusElement() && el.focusElementPreview()\n }\n }\n\n get collapseButton() {\n return this.querySelector(\"#collapse-all-elements-button\")\n }\n\n get toggleButton() {\n return document.querySelector(\"#element_window_button\")\n }\n\n get previewWindow() {\n return document.getElementById(\"alchemy_preview_window\")\n }\n\n get turboFrame() {\n if (!this.#turboFrame) {\n this.#turboFrame = this.closest(\"turbo-frame\")\n }\n return this.#turboFrame\n }\n\n get widthFromCookie() {\n return document.cookie\n .split(\"; \")\n .find((row) => row.startsWith(\"alchemy-elements-window-width=\"))\n ?.split(\"=\")[1]\n }\n\n set isDragged(dragged) {\n this.turboFrame.style.transitionProperty = dragged ? \"none\" : null\n this.turboFrame.style.pointerEvents = dragged ? \"none\" : null\n }\n\n #attachEvents() {\n this.collapseButton?.addEventListener(\"click\", () => {\n this.collapseAllElements()\n })\n window.addEventListener(\"message\", (event) => {\n const data = event.data\n if (data?.message == \"Alchemy.focusElementEditor\") {\n const element = document.getElementById(`element_${data.element_id}`)\n this.show()\n element?.focusElement()\n }\n })\n document.body.addEventListener(\"click\", (evt) => {\n if (!evt.target.closest(\"alchemy-element-editor\")) {\n this.querySelectorAll(\"alchemy-element-editor\").forEach((editor) => {\n editor.classList.remove(\"selected\")\n })\n this.previewWindow?.postMessage({ message: \"Alchemy.blurElements\" })\n }\n })\n }\n}\n\ncustomElements.define(\"alchemy-elements-window\", ElementsWindow)\n","class ElementsWindowHandle extends HTMLElement {\n #dragging = false\n #elementsWindow = null\n #previewWindow = null\n\n constructor() {\n super()\n\n this.addEventListener(\"mousedown\", this)\n window.addEventListener(\"mousemove\", this)\n window.addEventListener(\"mouseup\", this)\n }\n\n handleEvent(event) {\n switch (event.type) {\n case \"mousedown\":\n event.stopPropagation()\n this.onMouseDown()\n break\n case \"mouseup\":\n this.onMouseUp()\n break\n case \"mousemove\":\n if (this.#dragging) {\n this.onDrag(event.pageX)\n }\n break\n }\n }\n\n onMouseDown() {\n this.#dragging = true\n this.elementsWindow.isDragged = true\n this.previewWindow.isDragged = true\n this.classList.add(\"is-dragged\")\n }\n\n onMouseUp() {\n this.#dragging = false\n this.elementsWindow.isDragged = false\n this.previewWindow.isDragged = false\n this.classList.remove(\"is-dragged\")\n }\n\n onDrag(pageX) {\n const elementWindowWidth = window.innerWidth - pageX\n this.elementsWindow.resize(elementWindowWidth)\n }\n\n get elementsWindow() {\n if (!this.#elementsWindow) {\n this.#elementsWindow = document.querySelector(\"alchemy-elements-window\")\n }\n return this.#elementsWindow\n }\n\n get previewWindow() {\n if (!this.#previewWindow) {\n this.#previewWindow = document.getElementById(\"alchemy_preview_window\")\n }\n return this.#previewWindow\n }\n}\n\ncustomElements.define(\"alchemy-elements-window-handle\", ElementsWindowHandle)\n","class FileEditor extends HTMLElement {\n constructor() {\n super()\n this.deleteLink = this.querySelector(\".remove_file_link\")\n this.fileIcon = this.querySelector(\".file_icon\")\n this.fileName = this.querySelector(\".file_name\")\n this.formFieldId = this.deleteLink?.dataset.formFieldId\n this.formField = this.querySelector(`#${this.formFieldId}`)\n this.deleteLink?.addEventListener(\"click\", this)\n }\n\n handleEvent(event) {\n if (event.type === \"click\") this.removeFile()\n event.stopPropagation()\n }\n\n removeFile() {\n this.formField.value = \"\"\n this.fileIcon.innerHTML = \"\"\n this.fileName.innerHTML = \"\"\n this.deleteLink?.classList.add(\"hidden\")\n this.closest(\"alchemy-element-editor\").setDirty(this.formField)\n }\n}\n\ncustomElements.define(\"alchemy-file-editor\", FileEditor)\n","const DEFAULT_DEBOUNCE_TIME = 150\n\nclass ListFilter extends HTMLElement {\n #debounceTimer\n\n constructor() {\n super()\n this.#attachEvents()\n }\n\n #attachEvents() {\n if (this.hotkey) {\n key(this.hotkey, () => {\n this.filterField.focus()\n return false\n })\n }\n this.filterField.addEventListener(\"keyup\", () => {\n clearTimeout(this.#debounceTimer)\n this.#debounceTimer = setTimeout(() => {\n const term = this.filterField.value\n this.clearButton.style.visibility = term ? \"visible\" : \"hidden\"\n this.filter(term)\n }, this.debounceTime)\n })\n this.clearButton.addEventListener(\"click\", (e) => {\n e.preventDefault()\n this.clear()\n })\n this.filterField.addEventListener(\"focus\", () =>\n key.setScope(\"list_filter\")\n )\n key(\"esc\", \"list_filter\", () => {\n this.clear()\n this.filterField.blur()\n })\n }\n\n disconnectedCallback() {\n if (this.hotkey) {\n key.unbind(this.hotkey)\n }\n key.unbind(\"esc\", \"list_filter\")\n }\n\n filter(term) {\n if (term === \"\") {\n this.clearButton.style.visibility = \"hidden\"\n }\n\n const matchedItems = []\n const itemsToShow = new Set()\n const lowerTerm = term.toLowerCase()\n\n // First pass: find matching items and mark their ancestors as visible too\n this.items.forEach((item) => {\n const name = item.getAttribute(this.nameAttribute)?.toLowerCase()\n // indexOf is much faster then match()\n if (name.indexOf(lowerTerm) !== -1) {\n matchedItems.push(item)\n itemsToShow.add(item)\n // Mark ancestor items as visible so nested matches stay visible\n let ancestor = item.parentElement?.closest(this.itemsSelector)\n while (ancestor) {\n itemsToShow.add(ancestor)\n ancestor = ancestor.parentElement?.closest(this.itemsSelector)\n }\n }\n })\n\n // Second pass: apply visibility\n this.items.forEach((item) => {\n item.classList.toggle(\"hidden\", !itemsToShow.has(item))\n })\n\n // Scroll into view if only one match\n if (matchedItems.length === 1) {\n matchedItems[0].scrollIntoView({ behavior: \"smooth\", block: \"nearest\" })\n }\n }\n\n clear() {\n this.filterField.value = \"\"\n this.clearButton.style.visibility = \"hidden\"\n this.items.forEach((item) => item.classList.remove(\"hidden\"))\n }\n\n get nameAttribute() {\n return this.getAttribute(\"name-attribute\") || \"name\"\n }\n\n get clearButton() {\n return this.querySelector('button[type=\"button\"]')\n }\n\n get filterField() {\n return this.querySelector('input[type=\"text\"]')\n }\n\n get items() {\n return document.querySelectorAll(this.itemsSelector)\n }\n\n get itemsSelector() {\n return this.getAttribute(\"items-selector\")\n }\n\n get debounceTime() {\n return parseInt(this.getAttribute(\"debounce-time\")) || DEFAULT_DEBOUNCE_TIME\n }\n\n get hotkey() {\n return this.getAttribute(\"hotkey\")\n }\n}\n\ncustomElements.define(\"alchemy-list-filter\", ListFilter)\n","const DISMISS_DELAY = 5000\n\nclass Message extends HTMLElement {\n #message\n\n constructor() {\n super()\n this.#message = this.innerHTML\n if (this.dismissable || this.type === \"error\") {\n this.addEventListener(\"click\", this)\n }\n }\n\n handleEvent(event) {\n if (event.type === \"click\") {\n this.dismiss()\n }\n }\n\n connectedCallback() {\n this.innerHTML = `\n \n ${this.dismissable && this.type === \"error\" ? '' : \"\"}\n ${this.#message}\n `\n if (this.dismissable && this.type !== \"error\") {\n setTimeout(() => {\n this.dismiss()\n }, this.dismissDelay)\n }\n }\n\n dismiss() {\n this.addEventListener(\"transitionend\", () => this.remove())\n this.classList.add(\"dismissed\")\n }\n\n get dismissable() {\n return this.hasAttribute(\"dismissable\")\n }\n\n get icon() {\n return this.getAttribute(\"icon\")\n }\n\n get type() {\n return this.getAttribute(\"type\") || \"notice\"\n }\n\n get dismissDelay() {\n return parseInt(\n this.noticesWrapper?.dataset.autoDismissDelay || DISMISS_DELAY\n )\n }\n\n get iconName() {\n switch (this.icon || this.type) {\n case \"warning\":\n case \"warn\":\n case \"alert\":\n return \"alert\"\n case \"notice\":\n return \"check\"\n case \"info\":\n case \"hint\":\n return \"information\"\n case \"error\":\n return \"bug\"\n default:\n return this.type\n }\n }\n\n get noticesWrapper() {\n return this.closest(\"#flash_notices\")\n }\n}\n\ncustomElements.define(\"alchemy-message\", Message)\n","import { growl } from \"alchemy_admin/growler\"\n\nclass Growl extends HTMLElement {\n connectedCallback() {\n growl(this.message, this.getAttribute(\"type\") || \"notice\")\n this.remove()\n }\n\n get message() {\n return this.getAttribute(\"message\") || this.innerHTML\n }\n}\n\ncustomElements.define(\"alchemy-growl\", Growl)\n","class Icon extends HTMLElement {\n static get observedAttributes() {\n return [\"name\", \"size\", \"icon-style\"]\n }\n\n constructor() {\n super()\n this.spriteUrl = document\n .querySelector('link[rel=\"preload\"][as=\"image\"]')\n .getAttribute(\"href\")\n }\n\n connectedCallback() {\n this.render()\n }\n\n attributeChangedCallback() {\n this.render()\n }\n\n render() {\n const sizeClass = this.size ? ` icon--${this.size}` : \"\"\n this.innerHTML = ``\n }\n\n set name(value) {\n this.setAttribute(\"name\", value)\n }\n\n get iconName() {\n return this.getAttribute(\"name\")\n }\n\n get size() {\n return this.getAttribute(\"size\")\n }\n\n get style() {\n const value = this.getAttribute(\"icon-style\")\n switch (value) {\n case \"none\":\n return \"\"\n case null:\n return \"-line\"\n default:\n return `-${value}`\n }\n }\n}\n\ncustomElements.define(\"alchemy-icon\", Icon)\n","export class IngredientGroup extends HTMLDetailsElement {\n #localStorageKey = \"Alchemy.expanded_ingredient_groups\"\n\n constructor() {\n super()\n\n this.addEventListener(\"toggle\", this)\n\n if (this.isInLocalStorage) {\n this.open = true\n }\n }\n\n /**\n * Toggle visibility of the ingredient fields in this group\n */\n handleEvent() {\n let expanded_ingredient_groups = this.localStorageItem\n\n if (this.open) {\n this.toggleIcon.name = \"arrow-down-s\"\n if (!this.isInLocalStorage) expanded_ingredient_groups.push(this.id)\n } else {\n this.toggleIcon.name = \"arrow-left-s\"\n expanded_ingredient_groups = expanded_ingredient_groups.filter(\n (value) => value !== this.id\n )\n }\n\n localStorage.setItem(\n this.#localStorageKey,\n JSON.stringify(expanded_ingredient_groups)\n )\n }\n\n get isInLocalStorage() {\n return this.localStorageItem.includes(this.id)\n }\n\n get localStorageItem() {\n const item = localStorage.getItem(this.#localStorageKey)\n\n if (!item) return []\n\n try {\n return JSON.parse(item)\n } catch (error) {\n console.error(error)\n return []\n }\n }\n\n get toggleIcon() {\n return this.querySelector(\"alchemy-icon\")\n }\n}\n\ncustomElements.define(\"alchemy-ingredient-group\", IngredientGroup, {\n extends: \"details\"\n})\n","class LinkButton extends HTMLButtonElement {\n constructor() {\n super()\n this.addEventListener(\"click\", this)\n this.classList.add(\"icon_button\")\n // Prevent accidental form submits if this component is wrapped inside a form\n this.setAttribute(\"type\", \"button\")\n this.innerHTML = ''\n }\n\n handleEvent(event) {\n const dialog = new Alchemy.LinkDialog({\n url: this.linkUrl,\n title: this.linkTitle,\n target: this.linkTarget,\n type: this.linkClass\n })\n dialog.open().then((link) => this.setLink(link))\n event.preventDefault()\n }\n\n setLink(link) {\n if (link.url === \"\") {\n this.classList.remove(\"linked\")\n this.dispatchEvent(new CustomEvent(\"alchemy:unlink\", { bubbles: true }))\n } else {\n this.classList.add(\"linked\")\n this.dispatchEvent(\n new CustomEvent(\"alchemy:link\", {\n bubbles: true,\n detail: link\n })\n )\n }\n }\n\n get linkUrl() {\n return this.linkButtons.linkUrlField.value\n }\n\n get linkTitle() {\n return this.linkButtons.linkTitleField.value\n }\n\n get linkTarget() {\n return this.linkButtons.linkTargetField.value\n }\n\n get linkClass() {\n return this.linkButtons.linkClassField.value\n }\n\n get linkButtons() {\n return this.closest(\"alchemy-link-buttons\")\n }\n}\n\ncustomElements.define(\"alchemy-link-button\", LinkButton, { extends: \"button\" })\n","class UnlinkButton extends HTMLButtonElement {\n constructor() {\n super()\n this.addEventListener(\"click\", this)\n this.classList.add(\"icon_button\")\n // Prevent accidental form submits if this component is wrapped inside a form\n this.setAttribute(\"type\", \"button\")\n this.linked = this.linked\n this.innerHTML =\n ''\n }\n\n handleEvent(event) {\n if (this.linked) {\n this.linked = false\n this.blur()\n this.dispatchEvent(new CustomEvent(\"alchemy:unlink\", { bubbles: true }))\n }\n event.preventDefault()\n }\n\n set linked(isLinked) {\n if (isLinked) {\n this.classList.replace(\"disabled\", \"linked\")\n this.removeAttribute(\"tabindex\")\n } else {\n this.classList.replace(\"linked\", \"disabled\")\n this.setAttribute(\"tabindex\", \"-1\")\n }\n }\n\n get linked() {\n return this.classList.contains(\"linked\")\n }\n}\n\ncustomElements.define(\"alchemy-unlink-button\", UnlinkButton, {\n extends: \"button\"\n})\n","import \"alchemy_admin/components/link_buttons/link_button\"\nimport \"alchemy_admin/components/link_buttons/unlink_button\"\n\nclass LinkButtons extends HTMLElement {\n constructor() {\n super()\n this.addEventListener(\"alchemy:link\", this)\n this.addEventListener(\"alchemy:unlink\", this)\n }\n\n handleEvent(event) {\n switch (event.type) {\n case \"alchemy:link\":\n this.setLink(event.detail)\n break\n case \"alchemy:unlink\":\n this.removeLink()\n }\n event.stopPropagation()\n }\n\n setLink(data) {\n this.linkUrlField.value = data.url\n this.linkUrlField.dispatchEvent(new Event(\"change\"))\n this.linkTitleField.value = data.title\n this.linkClassField.value = data.type\n this.linkTargetField.value = data.target\n\n this.unlinkButton.linked = true\n this.setElementDirty()\n }\n\n removeLink() {\n this.linkUrlField.value = \"\"\n this.linkUrlField.dispatchEvent(new Event(\"change\"))\n this.linkTitleField.value = \"\"\n this.linkClassField.value = \"\"\n this.linkTargetField.value = \"\"\n\n this.linkButton.classList.remove(\"linked\")\n this.unlinkButton.linked = false\n\n this.setElementDirty()\n }\n\n setElementDirty() {\n this.elementEditor.setDirty(this)\n }\n\n get linkButton() {\n return this.querySelector('[is=\"alchemy-link-button\"]')\n }\n\n get unlinkButton() {\n return this.querySelector('[is=\"alchemy-unlink-button\"]')\n }\n\n get ingredientEditor() {\n const ingredientId = this.dataset.ingredientId\n return this.parentElement.closest(`[data-ingredient-id='${ingredientId}']`)\n }\n\n get elementEditor() {\n return this.closest(\"alchemy-element-editor\")\n }\n\n get linkUrlField() {\n return this.ingredientEditor.querySelector(\"[data-link-value]\")\n }\n\n get linkTitleField() {\n return this.ingredientEditor.querySelector(\"[data-link-title]\")\n }\n\n get linkTargetField() {\n return this.ingredientEditor.querySelector(\"[data-link-target]\")\n }\n\n get linkClassField() {\n return this.ingredientEditor.querySelector(\"[data-link-class]\")\n }\n}\n\ncustomElements.define(\"alchemy-link-buttons\", LinkButtons)\n","export function formatFileSize(bytes) {\n let exponent = bytes === 0 ? 0 : Math.floor(Math.log(bytes) / Math.log(1024))\n\n // prevent format higher than GB\n if (exponent > 3) {\n exponent = 3\n }\n\n let value = (bytes / Math.pow(1024, exponent)).toFixed(2)\n return value + \" \" + [\"B\", \"kB\", \"MB\", \"GB\"][exponent]\n}\n","import { RemoteSelect } from \"alchemy_admin/components/remote_select\"\n\nclass NodeSelect extends RemoteSelect {\n _searchQuery(term, page) {\n return {\n filter: {\n name_or_page_name_cont: term,\n ...JSON.parse(this.queryParams)\n },\n page: page\n }\n }\n\n _renderResult(item) {\n return this._renderListEntry(item)\n }\n\n /**\n * html template for each list entry\n * @param {object} node\n * @param {string} term\n * @returns {string}\n * @private\n */\n _renderListEntry(node, term) {\n const ancestors = node.ancestors.map((a) => a.name)\n const seperator = ``\n\n return `\n
    \n \n
    \n \n ${ancestors.length > 0 ? ancestors.join(seperator) + seperator : \"\"}\n \n \n ${this._hightlightTerm(node.name, term)}\n \n
    \n
    \n ${node.url || \"\"}\n
    \n
    \n `\n }\n}\n\ncustomElements.define(\"alchemy-node-select\", NodeSelect)\n","import { AlchemyHTMLElement } from \"alchemy_admin/components/alchemy_html_element\"\nimport { formatFileSize } from \"alchemy_admin/utils/format\"\nimport { translate } from \"alchemy_admin/i18n\"\nimport { growl } from \"alchemy_admin/growler\"\n\nexport class FileUpload extends AlchemyHTMLElement {\n constructor() {\n super()\n\n this.file = null\n this.request = null\n\n this.progressEventLoaded = 0\n this.progressEventTotal = 0\n this.className = \"in-progress\"\n this.valid = true\n this.value = 0\n }\n\n /**\n * Initialize the component with file and request\n * @param {File} file\n * @param {XMLHttpRequest} request\n */\n initialize(file, request) {\n this.file = file\n this.request = request\n this.progressEventTotal = file ? file.size : 0\n\n this._validateFile()\n this._addRequestEventListener()\n }\n\n render() {\n return `\n \n
    \n ${this.file?.name}\n ${this.loadedSize}\n ${this.errorMessage}\n
    \n \n \n \n `\n }\n\n afterRender() {\n this.querySelector(\"button\").addEventListener(\"click\", () => this.cancel())\n\n if (this.file?.type.includes(\"image\")) {\n const reader = new FileReader()\n reader.readAsDataURL(this.file)\n reader.addEventListener(\"load\", () => {\n const image = new Image()\n image.src = reader.result\n this.prepend(image)\n })\n }\n }\n\n /**\n * cancel the upload\n */\n cancel() {\n if (!this.finished) {\n this.status = \"canceled\"\n this.request?.abort()\n this.dispatchCustomEvent(\"FileUpload.Change\")\n }\n }\n\n /**\n * validate given file with the `Alchemy.uploader_defaults` - configuration\n * @private\n */\n _validateFile() {\n const config = Alchemy.uploader_defaults\n const maxFileSize = config.file_size_limit * Math.pow(1024, 2) // in Byte\n let errorMessage = undefined\n\n if (this.file?.size > maxFileSize) {\n errorMessage = translate(\"Uploaded bytes exceed file size\")\n }\n\n const allowedFiletypes = this.file?.type.includes(\"image\")\n ? config.allowed_filetypes.alchemy_pictures\n : config.allowed_filetypes.alchemy_attachments\n\n const isFileFormatSupported =\n allowedFiletypes.includes(\"*\") ||\n allowedFiletypes.includes(\n this.file?.type.replace(/^\\w+\\/(\\w+)(\\+\\w+)?/i, \"$1\")\n )\n\n if (!isFileFormatSupported) {\n errorMessage = translate(\"File type not allowed\")\n }\n\n if (errorMessage) {\n this.valid = false\n this.errorMessage = errorMessage\n }\n }\n\n /**\n * register event listeners to react on request changes\n * @private\n */\n _addRequestEventListener() {\n // prevent errors if the component will be called without a request - object\n if (!this.request) {\n return\n }\n\n // update the progress bar and currently loaded size information\n this.request.upload.onprogress = (progressEvent) => {\n this.progressEvent = progressEvent\n }\n\n // triggers, when the upload is done\n this.request.onload = () => {\n if (this.request.status < 400) {\n this.status = \"successful\"\n growl(this.responseMessage)\n } else {\n this.status = \"failed\"\n this.errorMessage = this.responseMessage\n }\n this.dispatchCustomEvent(\"FileUpload.Change\")\n }\n\n // catch request errors\n this.request.onerror = () => {\n this.errorMessage = translate(\"An error occurred during the transaction\")\n }\n }\n\n /**\n * @returns {boolean}\n */\n get active() {\n return this.valid && this.status !== \"canceled\"\n }\n\n /**\n * @returns {string}\n */\n get errorMessage() {\n return this._errorMessage || \"\"\n }\n\n /**\n * @param {string} message\n */\n set errorMessage(message) {\n this._errorMessage = message\n const errorMessageContainer = this.querySelector(\".error-message\")\n if (errorMessageContainer) {\n errorMessageContainer.textContent = message\n }\n growl(message, \"error\")\n }\n\n /**\n * @returns {boolean}\n */\n get finished() {\n return [\"canceled\", \"successful\", \"failed\"].includes(this.status)\n }\n\n /**\n * format the loaded and total size and present that as a string\n * @returns {string}\n */\n get loadedSize() {\n return `${formatFileSize(this.progressEventLoaded)} / ${formatFileSize(\n this.progressEventTotal\n )}`\n }\n\n /**\n * @returns {HTMLProgressElement|undefined}\n */\n get progressElement() {\n return this.querySelector(\"sl-progress-bar\")\n }\n\n /**\n * @param {ProgressEvent} progressEvent\n */\n set progressEvent(progressEvent) {\n this.progressEventLoaded = progressEvent.loaded\n this.progressEventTotal = progressEvent.total\n\n this.value = Math.round((progressEvent.loaded / progressEvent.total) * 100)\n this.querySelector(\".loaded-size\").textContent = this.loadedSize\n }\n\n /**\n * @returns {string}\n */\n get responseMessage() {\n try {\n const response = JSON.parse(this.request.responseText)\n return response[\"message\"]\n } catch (error) {\n return `${this.request.status}: ${this.request.statusText}`\n }\n }\n\n /**\n * @returns {string}\n */\n get status() {\n return this._status\n }\n\n /**\n * @param {string} status\n */\n set status(status) {\n this._status = status\n this.className = status\n\n this.progressElement?.toggleAttribute(\n \"indeterminate\",\n status === \"upload-finished\"\n )\n }\n\n /**\n * @returns {boolean}\n */\n get valid() {\n return this._valid\n }\n\n /**\n * @param {boolean} isValid\n */\n set valid(isValid) {\n this._valid = isValid\n this.classList.toggle(\"invalid\", !isValid)\n }\n\n /**\n * get the progress value of the current file\n * @returns {number}\n */\n get value() {\n return this._value\n }\n\n /**\n * @param {number} value\n */\n set value(value) {\n this._value = value\n if (this.progressElement) {\n this.progressElement.value = value\n }\n\n if (value === 100) {\n this.status = \"upload-finished\"\n }\n\n this.dispatchCustomEvent(\"FileUpload.Change\")\n }\n}\n\ncustomElements.define(\"alchemy-file-upload\", FileUpload)\n","import { AlchemyHTMLElement } from \"alchemy_admin/components/alchemy_html_element\"\nimport { FileUpload } from \"alchemy_admin/components/uploader/file_upload\"\nimport { formatFileSize } from \"alchemy_admin/utils/format\"\nimport { translate } from \"alchemy_admin/i18n\"\n\nexport class Progress extends AlchemyHTMLElement {\n #visible = false\n\n constructor() {\n super()\n this.buttonLabel = translate(\"Cancel all uploads\")\n this.fileUploads = []\n this.fileCount = 0\n this.className = \"in-progress\"\n this.visible = true\n this.handleFileChange = () => this._updateView()\n }\n\n /**\n * Initialize the component with file uploads\n * @param {FileUpload[]} fileUploads\n */\n initialize(fileUploads = []) {\n this.fileUploads = fileUploads\n this.fileCount = fileUploads.length\n }\n\n /**\n * append file progress - components for each file\n */\n afterRender() {\n this.actionButton = this.querySelector(\"button\")\n this.actionButton.addEventListener(\"click\", () => {\n if (this.finished) {\n this.onComplete(this.status)\n } else {\n this.cancel()\n }\n })\n\n this.fileUploads.forEach((fileUpload) => {\n this.querySelector(\".single-uploads\").append(fileUpload)\n })\n }\n\n /**\n * cancel requests in all remaining uploads\n */\n cancel() {\n this._activeUploads().forEach((upload) => {\n upload.cancel()\n })\n this._setupCloseButton()\n }\n\n /**\n * update view and register change event\n */\n connected() {\n this._updateView()\n this.addEventListener(\"Alchemy.FileUpload.Change\", this.handleFileChange)\n }\n\n /**\n * deregister file upload change - event\n */\n disconnected() {\n this.removeEventListener(\"Alchemy.FileUpload.Change\", this.handleFileChange)\n }\n\n /**\n * a complete hook to allow the uploader to react and trigger an event\n * it would be possible to trigger the event here, but the dispatching would happen\n * in the scope of that component and can't be cached o uploader - component level\n */\n onComplete(_status) {}\n\n render() {\n return `\n \n
    \n \n\n \n \n \n
    \n
    3 ? 3 : this.fileCount\n }\">
    \n
    \n `\n }\n\n /**\n * get all active upload components\n * @returns {FileUpload[]}\n * @private\n */\n _activeUploads() {\n return this.fileUploads.filter((upload) => upload.active)\n }\n\n /**\n * replace cancel button to be the close button\n * @private\n */\n _setupCloseButton() {\n this.buttonLabel = translate(\"Close\")\n this.actionButton.ariaLabel = this.buttonLabel\n this.actionButton.parentElement.content = this.buttonLabel // update tooltip content\n }\n\n /**\n * @param {string} field\n * @returns {number}\n * @private\n */\n _sumFileProgresses(field) {\n return this._activeUploads().reduce(\n (accumulator, upload) => upload[field] + accumulator,\n 0\n )\n }\n\n /**\n * don't render the whole element new, because it would prevent selecting buttons\n * @private\n */\n _updateView() {\n const status = this.status\n this.className = status\n\n // update progress bar\n this.progressElement.value = this.totalProgress\n this.progressElement.toggleAttribute(\n \"indeterminate\",\n status === \"upload-finished\"\n )\n\n // show progress in file size and percentage\n this.querySelector(`.overall-progress-value > span`).textContent =\n this.overallProgressValue\n this.querySelector(`.overall-upload-value`).textContent =\n this.overallUploadSize\n\n if (this.finished) {\n this._setupCloseButton()\n this.onComplete(status)\n } else {\n this.visible = true\n }\n }\n\n /**\n * @returns {boolean}\n */\n get finished() {\n return this._activeUploads().every((entry) => entry.finished)\n }\n\n /**\n * @returns {string}\n */\n get overallUploadSize() {\n const uploadedFileCount = this._activeUploads().filter(\n (fileProgress) => fileProgress.value >= 100\n ).length\n const overallProgressValue = `${\n this.totalProgress\n }% (${uploadedFileCount} / ${this._activeUploads().length})`\n\n return `${formatFileSize(\n this._sumFileProgresses(\"progressEventLoaded\")\n )} / ${formatFileSize(this._sumFileProgresses(\"progressEventTotal\"))}`\n }\n\n /**\n * @returns {string}\n */\n get overallProgressValue() {\n const uploadedFileCount = this._activeUploads().filter(\n (fileProgress) => fileProgress.value >= 100\n ).length\n return `${this.totalProgress}% (${uploadedFileCount} / ${\n this._activeUploads().length\n })`\n }\n\n /**\n * @returns {HTMLProgressElement|undefined}\n */\n get progressElement() {\n return this.querySelector(\"sl-progress-bar\")\n }\n\n /**\n * get status of file progresses and accumulate the overall status\n * @returns {string}\n */\n get status() {\n const uploadsStatuses = this._activeUploads().map(\n (upload) => upload.className\n )\n\n // mark as failed, if any upload failed\n if (uploadsStatuses.includes(\"failed\")) {\n return \"failed\"\n }\n\n // no active upload means that every upload was canceled\n if (uploadsStatuses.length === 0) {\n return \"canceled\"\n }\n\n // all uploads are successful or upload-finished or in-progress\n if (uploadsStatuses.every((entry) => entry === uploadsStatuses[0])) {\n return uploadsStatuses[0]\n }\n\n return \"in-progress\"\n }\n\n /**\n * @returns {number}\n */\n get totalProgress() {\n const totalSize = this._activeUploads().reduce(\n (accumulator, upload) => accumulator + upload.file.size,\n 0\n )\n let totalProgress = Math.ceil(\n this._activeUploads().reduce((accumulator, upload) => {\n const weight = upload.file.size / totalSize\n return upload.value * weight + accumulator\n }, 0)\n )\n // prevent rounding errors\n if (totalProgress > 100) {\n totalProgress = 100\n }\n return totalProgress\n }\n\n /**\n * @returns {boolean}\n */\n get visible() {\n return this.#visible\n }\n\n /**\n * @param {boolean} visible\n */\n set visible(visible) {\n this.classList.toggle(\"visible\", visible)\n this.#visible = visible\n }\n}\n\ncustomElements.define(\"alchemy-upload-progress\", Progress)\n","/**\n * @typedef {object} PersistedFile\n * @property {string} name\n * @property {number} size\n */\nimport { AlchemyHTMLElement } from \"alchemy_admin/components/alchemy_html_element\"\nimport { Progress } from \"alchemy_admin/components/uploader/progress\"\nimport { FileUpload } from \"alchemy_admin/components/uploader/file_upload\"\nimport { translate } from \"alchemy_admin/i18n\"\nimport { getToken } from \"alchemy_admin/utils/ajax\"\n\nexport class Uploader extends AlchemyHTMLElement {\n static properties = {\n dropzone: { default: false }\n }\n\n connected() {\n this.fileInput.addEventListener(\"change\", (event) => {\n this._uploadFiles(Array.from(event.target.files))\n })\n if (this.dropzone) {\n this._dragAndDropBehavior()\n }\n this.addEventListener(\"Alchemy.upload.successful\", this)\n }\n\n handleEvent(evt) {\n switch (evt.type) {\n case \"Alchemy.upload.successful\":\n this._handleUploadComplete()\n break\n }\n }\n\n _handleUploadComplete() {\n setTimeout(() => {\n const url = this.redirectUrl\n const turboFrame = this.closest(\"turbo-frame\")\n this.uploadProgress.visible = false\n\n if (!url) return\n\n if (turboFrame) {\n turboFrame.setAttribute(\"src\", url)\n turboFrame.reload()\n } else {\n Turbo.visit(url)\n }\n }, 750)\n }\n\n /**\n * add dragover class to indicate, if the file is draggable\n * @private\n */\n _dragAndDropBehavior() {\n const dropzoneElement = document.querySelector(this.dropzone)\n let isDraggedOver = false\n\n const toggleDropzoneClass = (enabled) => {\n if (isDraggedOver !== enabled) {\n isDraggedOver = enabled\n dropzoneElement.classList.toggle(\"dragover\")\n }\n }\n\n dropzoneElement.addEventListener(\"dragleave\", () =>\n toggleDropzoneClass(false)\n )\n dropzoneElement.addEventListener(\"drop\", async (event) => {\n event.preventDefault()\n toggleDropzoneClass(false)\n\n const files = [...event.dataTransfer.items].map((item) =>\n item.getAsFile()\n )\n\n this._uploadFiles(files)\n })\n\n dropzoneElement.addEventListener(\"dragover\", (event) => {\n event.preventDefault() // dragover has to be disabled to use the custom drop event\n toggleDropzoneClass(true)\n })\n }\n\n /**\n * @param {File[]} files\n * @private\n */\n _uploadFiles(files) {\n // prepare file progress bars and server request\n let fileUploadCount = 0\n\n const fileUploads = files.map((file) => {\n const request = new XMLHttpRequest()\n const fileUpload = new FileUpload()\n fileUpload.initialize(file, request)\n\n if (Alchemy.uploader_defaults.upload_limit - 1 < fileUploadCount) {\n fileUpload.valid = false\n fileUpload.errorMessage = translate(\"Maximum number of files exceeded\")\n } else if (fileUpload.valid) {\n fileUploadCount++\n this._submitFile(request, file)\n }\n\n return fileUpload\n })\n\n this._createProgress(fileUploads)\n }\n\n /**\n * @param {XMLHttpRequest} request\n * @param {File} file\n * @private\n */\n _submitFile(request, file) {\n const form = this.querySelector(\"form\")\n const formData = new FormData(form)\n formData.set(this.fileInput.name, file)\n request.open(\"POST\", form.action)\n request.setRequestHeader(\"X-CSRF-Token\", getToken())\n request.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\")\n request.setRequestHeader(\"Accept\", \"application/json\")\n request.send(formData)\n }\n\n /**\n * create (and maybe remove the old) progress bar - component\n * @param {FileUpload[]} fileUploads\n * @private\n */\n _createProgress(fileUploads) {\n if (this.uploadProgress) {\n this.uploadProgress.cancel()\n document.body.removeChild(this.uploadProgress)\n }\n this.uploadProgress = new Progress()\n this.uploadProgress.initialize(fileUploads)\n this.uploadProgress.onComplete = (status) => {\n this.dispatchCustomEvent(`upload.${status}`)\n }\n\n document.body.append(this.uploadProgress)\n }\n\n /**\n * @returns {HTMLInputElement}\n */\n get fileInput() {\n return this.querySelector(\"input[type='file']\")\n }\n\n get redirectUrl() {\n return this.getAttribute(\"redirect-url\")\n }\n}\n\ncustomElements.define(\"alchemy-uploader\", Uploader)\n","import { AlchemyHTMLElement } from \"alchemy_admin/components/alchemy_html_element\"\n\nclass Overlay extends AlchemyHTMLElement {\n render() {\n return `\n \n
    \n ${this.getAttribute(\"text\")}\n
    \n `\n }\n\n set show(value) {\n this.classList.toggle(\"visible\", value)\n }\n}\n\ncustomElements.define(\"alchemy-overlay\", Overlay)\n","import { patch } from \"alchemy_admin/utils/ajax\"\nimport { growl } from \"alchemy_admin/growler\"\nimport Spinner from \"alchemy_admin/spinner\"\n\nconst BUTTON = \"BUTTON\"\nconst SPAN = \"SPAN\"\n\n/**\n * Custom element for page nodes in the sitemap tree\n * Handles folding/unfolding of page children\n */\nexport class AlchemyPageNode extends HTMLElement {\n connectedCallback() {\n this.pageId = this.getAttribute(\"page-id\")\n this.folded = this.hasAttribute(\"folded\")\n\n this.folderButton?.addEventListener(\"click\", this)\n }\n\n disconnectedCallback() {\n this.folderButton?.removeEventListener(\"click\", this)\n }\n\n async handleEvent(event) {\n if (event.type === \"click\") {\n await this.handleFolderClick(event)\n }\n }\n\n async handleFolderClick(event) {\n event.preventDefault()\n event.stopPropagation()\n\n const folderButton = event.currentTarget\n folderButton.innerHTML = \"\"\n const spinner = new Spinner(\"small\")\n spinner.spin(folderButton)\n\n try {\n await patch(\n Alchemy.routes.fold_admin_page_path(this.pageId),\n null,\n \"text/vnd.turbo-stream.html\"\n )\n\n this.folded = !this.folded\n this.toggleAttribute(\"folded\", this.folded)\n this.toggleChildren()\n this.updateFolderIcon()\n } catch (error) {\n growl(error.message || error, \"error\")\n this.updateFolderIcon()\n } finally {\n spinner.stop()\n }\n }\n\n toggleChildren() {\n const childrenContainer = this.querySelector(\n `#page_${this.pageId}_children`\n )\n if (childrenContainer) {\n childrenContainer.classList.toggle(\"hidden\", this.folded)\n }\n }\n\n updateFolderIcon() {\n if (this.folderButton) {\n const iconName = this.folded ? \"arrow-right-s\" : \"arrow-down-s\"\n this.folderButton.innerHTML = ``\n }\n }\n\n /**\n * Updates the folder button state based on whether the node has children\n * Converts between button and span as needed\n */\n updateFolderButton() {\n const folderElement = this.querySelector(\".page_folder\")\n if (!folderElement) return\n\n const shouldShowButton = this.hasChildren || this.folded\n\n if (shouldShowButton && folderElement.tagName === SPAN) {\n // Convert span to button with icon\n const iconName = this.folded ? \"arrow-right-s\" : \"arrow-down-s\"\n folderElement.outerHTML = ``\n\n // Re-attach event listener to the new button element\n this.folderButton?.addEventListener(\"click\", this)\n } else if (!shouldShowButton && folderElement.tagName === BUTTON) {\n // Convert button to empty span (no children and not folded)\n folderElement.outerHTML = ''\n } else if (shouldShowButton && folderElement.tagName === BUTTON) {\n // Button exists, just update the icon direction\n this.updateFolderIcon()\n }\n }\n\n get hasChildren() {\n const childrenContainer = this.querySelector(\n `#page_${this.pageId}_children`\n )\n if (!childrenContainer) return false\n\n return (\n childrenContainer.querySelectorAll(\":scope > alchemy-page-node\").length >\n 0\n )\n }\n\n get folderButton() {\n return this.querySelector(\"button.page_folder\")\n }\n}\n\ncustomElements.define(\"alchemy-page-node\", AlchemyPageNode)\n","// Handles the page publication date fields\nexport class PagePublicationFields extends HTMLElement {\n connectedCallback() {\n const public_on_picker = this.querySelector(\n \"alchemy-datepicker:has(#page_public_on)\"\n )\n const public_until_picker = this.querySelector(\n \"alchemy-datepicker:has(#page_public_until)\"\n )\n const publication_date_fields = this.querySelector(\n \".page-publication-date-fields\"\n )\n const public_field = this.querySelector(\"#page_public\")\n\n if (!public_field) return\n\n public_field.addEventListener(\"click\", function (evt) {\n const checkbox = evt.target\n const now = new Date()\n\n if (checkbox.checked) {\n publication_date_fields.classList.remove(\"hidden\")\n public_on_picker.flatpickr.setDate(now)\n } else {\n publication_date_fields.classList.add(\"hidden\")\n public_on_picker.flatpickr.clear()\n }\n public_until_picker.flatpickr?.clear()\n })\n }\n}\n\ncustomElements.define(\"alchemy-page-publication-fields\", PagePublicationFields)\n","import { RemoteSelect } from \"alchemy_admin/components/remote_select\"\n\nclass PageSelect extends RemoteSelect {\n get pageId() {\n return this.selection ? JSON.parse(this.selection)[\"id\"] : undefined\n }\n\n _searchQuery(term, page) {\n return {\n q: {\n name_cont: term,\n ...JSON.parse(this.queryParams)\n },\n page: page\n }\n }\n\n _parseResponse(response) {\n const meta = response.meta\n return {\n results: response.pages,\n more: meta.page * meta.per_page < meta.total_count\n }\n }\n\n /**\n * result which is visible if a page was selected\n * @param {object} page\n * @returns {string}\n * @private\n */\n _renderResult(page) {\n return page.text || page.name\n }\n\n /**\n * html template for each list entry\n * @param {object} page\n * @param {string} term\n * @returns {string}\n * @private\n */\n _renderListEntry(page, term) {\n return `\n
    \n
    \n \n ${this._hightlightTerm(page.name, term)}\n ${page.site.name}\n
    \n
    \n ${page.url_path}\n ${page.language_code}\n
    \n
    \n `\n }\n}\n\ncustomElements.define(\"alchemy-page-select\", PageSelect)\n","class PictureDescriptionSelect extends HTMLElement {\n constructor() {\n super()\n this.addEventListener(\"change\", this)\n }\n\n handleEvent(event) {\n switch (event.type) {\n case \"change\":\n this.onChange()\n break\n }\n }\n\n onChange() {\n const url = new URL(this.getAttribute(\"url\"))\n const select = this.querySelector(\"select\")\n url.searchParams.set(\"language_id\", select.value)\n Turbo.visit(url, { frame: \"picture_descriptions\" })\n }\n}\n\ncustomElements.define(\n \"alchemy-picture-description-select\",\n PictureDescriptionSelect\n)\n","import debounce from \"alchemy_admin/utils/debounce\"\nimport max from \"alchemy_admin/utils/max\"\nimport { get } from \"alchemy_admin/utils/ajax\"\nimport { growl } from \"alchemy_admin/growler\"\n\nconst UPDATE_DELAY = 125\nconst IMAGE_PLACEHOLDER = ''\nconst THUMBNAIL_SIZE = \"160x120\"\n\nexport class PictureEditor extends HTMLElement {\n constructor() {\n super()\n\n this.cropFromField = this.querySelector(\"[data-crop-from]\")\n this.cropSizeField = this.querySelector(\"[data-crop-size]\")\n this.pictureIdField = this.querySelector(\"[data-picture-id]\")\n this.targetSizeField = this.querySelector(\"[data-target-size]\")\n this.imageCropperField = this.querySelector(\"[data-image-cropper]\")\n this.image = this.querySelector(\"img\")\n this.pictureThumbnail = this.querySelector(\"alchemy-picture-thumbnail\")\n this.deleteButton = this.querySelector(\".picture_tool.delete\")\n this.cropLink = this.querySelector(\".crop_link\")\n\n this.targetSize = this.targetSizeField.dataset.targetSize\n this.pictureId = this.pictureIdField.value\n\n // The mutation observer is observing multiple fields that all get updated\n // simultaneously. We only want to update the image once, so we debounce.\n this.update = debounce(() => {\n this.updateImage()\n this.updateCropLink()\n }, UPDATE_DELAY)\n\n this.deleteButton?.addEventListener(\"click\", this.removeImage.bind(this))\n }\n\n connectedCallback() {\n this.observer = new MutationObserver(this.mutationCallback.bind(this))\n\n this.observer.observe(this.cropFromField, { attributes: true })\n this.observer.observe(this.cropSizeField, { attributes: true })\n this.observer.observe(this.pictureIdField, { attributes: true })\n }\n\n disconnectedCallback() {\n this.observer.disconnect()\n }\n\n mutationCallback(mutationsList) {\n for (const mutation of mutationsList) {\n if (\"pictureId\" in mutation.target.dataset) {\n this.cropFromField.value = \"\"\n this.cropSizeField.value = \"\"\n this.pictureId = mutation.target.value\n }\n this.update()\n }\n }\n\n updateImage() {\n if (!this.pictureId) return\n\n this.pictureThumbnail.loading = true\n get(Alchemy.routes.url_admin_picture_path(this.pictureId), {\n crop: this.imageCropperEnabled,\n crop_from: this.cropFrom,\n crop_size: this.cropSize,\n flatten: true,\n size: THUMBNAIL_SIZE\n })\n .then(({ data }) => {\n this.pictureThumbnail.src = data.url\n this.pictureThumbnail.image.alt = data.alt\n this.pictureThumbnail.image.title = data.title\n this.setElementDirty()\n })\n .catch((error) => {\n console.error(error.message || error)\n growl(error.message || error, \"error\")\n })\n }\n\n removeImage() {\n this.pictureThumbnail.innerHTML = IMAGE_PLACEHOLDER\n this.pictureIdField.value = \"\"\n this.image = null\n this.cropLink.classList.add(\"disabled\")\n this.setElementDirty()\n }\n\n setElementDirty() {\n this.closest(\".element-editor\").setDirty(this)\n }\n\n updateCropLink() {\n if (!this.pictureId || !this.imageCropperEnabled) return\n\n this.cropLink.classList.remove(\"disabled\")\n\n if (this.cropLink.href.match(/(picture_id=)\\d+/)) {\n this.cropLink.href = this.cropLink.href.replace(\n /(picture_id=)\\d+/,\n \"$1\" + this.pictureId\n )\n } else {\n this.cropLink.href = this.cropLink.href + `&picture_id=${this.pictureId}`\n }\n }\n\n get cropFrom() {\n if (this.cropFromField.value === \"\") {\n return this.defaultCropFrom.join(\"x\")\n }\n return this.cropFromField.value\n }\n\n get cropSize() {\n if (this.cropSizeField.value === \"\") {\n return this.defaultCropSize.join(\"x\")\n }\n return this.cropSizeField.value\n }\n\n get defaultCropSize() {\n if (!this.imageCropperEnabled) return []\n\n const mask = this.targetSize.split(\"x\").map((n) => parseInt(n))\n const zoom = max(\n mask[0] / this.imageFileWidth,\n mask[1] / this.imageFileHeight\n )\n\n return [Math.round(mask[0] / zoom), Math.round(mask[1] / zoom)]\n }\n\n get defaultCropFrom() {\n if (!this.imageCropperEnabled) return []\n\n const dimensions = this.defaultCropSize\n\n return [\n Math.round((this.imageFileWidth - dimensions[0]) / 2),\n Math.round((this.imageFileHeight - dimensions[1]) / 2)\n ]\n }\n\n get imageFileWidth() {\n return parseInt(this.pictureIdField.dataset.imageFileWidth)\n }\n\n get imageFileHeight() {\n return parseInt(this.pictureIdField.dataset.imageFileHeight)\n }\n\n get imageCropperEnabled() {\n return this.targetSizeField.dataset.imageCropper === \"true\"\n }\n}\n\ncustomElements.define(\"alchemy-picture-editor\", PictureEditor)\n","export default function (func, delay) {\n let timeout\n\n return function (...args) {\n const that = this\n\n clearTimeout(timeout)\n timeout = setTimeout(() => func.apply(that, args), delay)\n }\n}\n","export default function (a, b) {\n return a >= b ? a : b\n}\n","// Shows spinner while loading images and\n// fades the image after its been loaded\n\nimport Spinner from \"alchemy_admin/spinner\"\n\nexport default class PictureThumbnail extends HTMLElement {\n constructor() {\n super()\n\n this.classList.add(\"thumbnail_background\")\n this.spinner = new Spinner(\"small\")\n\n if (this.src) {\n this.start()\n }\n }\n\n handleEvent(evt) {\n switch (evt.type) {\n case \"load\":\n this.#onLoaded()\n break\n case \"error\":\n this.#onError(evt)\n break\n default:\n break\n }\n }\n\n connectedCallback() {\n this.#setImage()\n }\n\n disconnectedCallback() {\n this.image?.removeEventListener(\"load\", this)\n this.image?.removeEventListener(\"error\", this)\n this.stop()\n }\n\n createImage(src = this.src, alt = this.name) {\n this.image = new Image()\n this.image.src = src\n if (alt) {\n this.image.alt = alt\n }\n }\n\n start(src) {\n this.createImage(src)\n this.image.addEventListener(\"load\", this)\n this.image.addEventListener(\"error\", this)\n this.load()\n }\n\n load() {\n if (this.image?.complete) {\n return\n }\n this.setAttribute(\"loading\", \"loading\")\n this.innerHTML = \"\"\n this.spinner.spin(this)\n }\n\n stop() {\n this.classList.remove(\"loading\")\n this.spinner.stop()\n }\n\n #onLoaded() {\n this.spinner.stop()\n this.removeAttribute(\"loading\")\n }\n\n #onError(evt) {\n const message = `Could not load ${this.image.src}`\n const hoist = this.closest(\".ingredient-editor\")\n this.spinner.stop()\n this.innerHTML = `\n \n \n \n `\n console.error(message, evt)\n }\n\n #setImage() {\n if (this.image?.complete) {\n this.replaceChildren(this.image)\n } else if (this.image) {\n this.append(this.image)\n }\n }\n\n set loading(value) {\n value ? this.load() : this.stop()\n }\n\n set src(src) {\n this.start(src)\n this.#setImage()\n }\n\n get name() {\n return this.getAttribute(\"name\")\n }\n\n get src() {\n return this.getAttribute(\"src\")\n }\n}\n\ncustomElements.define(\"alchemy-picture-thumbnail\", PictureThumbnail)\n","class PublishPageButton extends HTMLElement {\n constructor() {\n super()\n this.addEventListener(\"submit\", this)\n }\n\n connectedCallback() {\n document.addEventListener(\"alchemy:page-dirty\", this)\n }\n\n disconnectedCallback() {\n document.removeEventListener(\"alchemy:page-dirty\", this)\n }\n\n handleEvent(event) {\n switch (event.type) {\n case \"alchemy:page-dirty\":\n this.markDirty(event.detail)\n break\n case \"submit\":\n this.button.loading = true\n break\n }\n }\n\n markDirty(detail) {\n this.button.variant = \"primary\"\n this.button.disabled = false\n this.tooltip.content = detail.tooltip\n }\n\n get button() {\n return this.querySelector(\"sl-button\")\n }\n\n get tooltip() {\n return this.querySelector(\"sl-tooltip\")\n }\n}\n\ncustomElements.define(\"alchemy-publish-page-button\", PublishPageButton)\n","class Select extends HTMLSelectElement {\n #select2Element\n\n connectedCallback() {\n this.classList.add(\"alchemy_selectbox\")\n\n this.#select2Element = $(this).select2({\n minimumResultsForSearch: 5,\n dropdownAutoWidth: true,\n allowClear: !!this.allowClear\n })\n\n // For single selects, remove the close button if allowClear is not set\n // For multiple selects, always keep the close buttons\n if (!this.allowClear && !this.multiple) {\n this.#select2Element\n .prev(\".select2-container\")\n .find(\".select2-search-choice-close\")\n .remove()\n }\n }\n\n enable() {\n this.removeAttribute(\"disabled\")\n this.#updateSelect2()\n }\n\n disable() {\n this.setAttribute(\"disabled\", \"disabled\")\n this.#updateSelect2()\n }\n\n setOptions(data, prompt = undefined) {\n let selectedValue = this.value\n\n // reset the old options and insert the placeholder(s) first\n this.innerHTML = \"\"\n if (prompt) {\n this.add(new Option(prompt, \"\"))\n }\n\n // add the new options to the select\n data.forEach((item) => {\n this.add(new Option(item.text, item.id, false, item.id === selectedValue))\n })\n\n this.#updateSelect2()\n }\n\n /**\n * inform Select2 to update\n */\n #updateSelect2() {\n this.#select2Element.trigger(\"change\")\n }\n\n get allowClear() {\n return this.dataset.hasOwnProperty(\"allowClear\") || this.multiple\n }\n}\n\ncustomElements.define(\"alchemy-select\", Select, { extends: \"select\" })\n","import Sortable from \"sortablejs\"\nimport { growl } from \"alchemy_admin/growler\"\nimport { patch } from \"alchemy_admin/utils/ajax\"\nimport { translate } from \"alchemy_admin/i18n\"\nimport pleaseWaitOverlay from \"alchemy_admin/please_wait_overlay\"\n\n/**\n * Custom element for the sitemap container\n * Handles search/filter functionality and drag-and-drop sorting\n */\nexport class AlchemySitemap extends HTMLElement {\n connectedCallback() {\n this.searchInput = document.querySelector(\".search_input_field\")\n this.clearButton = document.querySelector(\"#search_field_clear\")\n this.resultCounter = document.querySelector(\"#page_filter_result\")\n\n this.setupSearch()\n\n // Wait for child custom elements to be defined before setting up sortables\n requestAnimationFrame(() => {\n this.setupSortables()\n })\n\n // Set up MutationObserver to re-initialize sortables when children containers are added\n this.observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n mutation.addedNodes.forEach((node) => {\n if (node.nodeType !== Node.ELEMENT_NODE) return\n\n // If the added node itself is a children container, initialize it\n if (node.classList?.contains(\"children\")) {\n this.setupSortable(node)\n }\n\n // Also check for children containers nested within the added node\n // This handles cases where a parent element with nested children is added at once\n node\n .querySelectorAll(\".children\")\n .forEach((el) => this.setupSortable(el))\n })\n })\n })\n\n // Observe the sitemap for added nodes\n this.observer.observe(this, {\n childList: true,\n subtree: true\n })\n }\n\n disconnectedCallback() {\n this.teardownSearch()\n this.observer?.disconnect()\n }\n\n setupSearch() {\n this.searchInput?.addEventListener(\"input\", this)\n this.clearButton?.addEventListener(\"click\", this)\n }\n\n teardownSearch() {\n this.searchInput?.removeEventListener(\"input\", this)\n this.clearButton?.removeEventListener(\"click\", this)\n }\n\n handleEvent(event) {\n if (event.type === \"input\" && event.target === this.searchInput) {\n this.handleSearch(event)\n } else if (event.type === \"click\" && event.target === this.clearButton) {\n this.handleClearSearch(event)\n }\n }\n\n handleSearch(event) {\n const term = event.target.value.toLowerCase().trim()\n\n if (term === \"\") {\n this.clearFilter()\n return\n }\n\n this.filterPages(term)\n }\n\n filterPages(term) {\n const allPages = this.querySelectorAll(\".sitemap_page\")\n let matchCount = 0\n let firstMatch = null\n\n allPages.forEach((pageElement) => {\n const pageName = pageElement.getAttribute(\"name\") || \"\"\n\n if (pageName.toLowerCase().includes(term)) {\n pageElement.classList.add(\"highlight\")\n pageElement.classList.remove(\"no-match\")\n matchCount++\n if (!firstMatch) firstMatch = pageElement\n } else {\n pageElement.classList.remove(\"highlight\")\n pageElement.classList.add(\"no-match\")\n }\n })\n\n // Update result counter\n\n if (matchCount === 1) {\n this.resultCounter.textContent = `1 ${translate(\"page_found\")}`\n this.resultCounter.style.display = \"block\"\n } else if (matchCount > 1) {\n this.resultCounter.textContent = `${matchCount} ${translate(\"pages_found\")}`\n this.resultCounter.style.display = \"block\"\n } else {\n this.resultCounter.style.display = \"none\"\n }\n\n // Scroll first match into view\n if (firstMatch) {\n firstMatch.scrollIntoView({ behavior: \"smooth\", block: \"center\" })\n }\n }\n\n clearFilter() {\n const allPages = this.querySelectorAll(\".sitemap_page\")\n allPages.forEach((pageElement) => {\n pageElement.classList.remove(\"highlight\", \"no-match\")\n })\n\n this.resultCounter.style.display = \"none\"\n }\n\n handleClearSearch(event) {\n event.preventDefault()\n this.searchInput.value = \"\"\n this.clearFilter()\n }\n\n setupSortable(container) {\n new Sortable(container, {\n group: \"pages\",\n animation: 150,\n fallbackOnBody: true,\n swapThreshold: 0.65,\n handle: \".page-icon.handle\",\n draggable: \"alchemy-page-node\",\n onEnd: (evt) => this.handleSort(evt)\n })\n }\n\n setupSortables() {\n const sortables = this.querySelectorAll(\".children\")\n sortables.forEach((el) => this.setupSortable(el))\n }\n\n async handleSort(evt) {\n // Only proceed if actually moved to different position/container\n if (evt.from === evt.to && evt.oldIndex === evt.newIndex) {\n return\n }\n\n // evt.item is the element being dragged\n const pageNode = evt.item\n const pageId = pageNode.pageId\n const url = Alchemy.routes.move_admin_page_path(pageId)\n const data = {\n target_parent_id: evt.to.dataset.parentId,\n new_position: evt.newIndex\n }\n\n pleaseWaitOverlay(true)\n\n try {\n const response = await patch(url, data)\n const pageData = await response.data\n\n // Update the URL path of the moved page\n const pageEl = pageNode.querySelector(`#page_${pageId}`)\n if (pageEl) {\n const urlPathEl = pageEl.querySelector(\".sitemap_url\")\n if (urlPathEl && pageData.url_path) {\n urlPathEl.textContent = pageData.url_path\n }\n }\n\n // Update folder icons for affected parent pages\n this.updateFolderIcons(evt.from, evt.to)\n\n growl(translate(\"Successfully moved page\"))\n } catch (error) {\n growl(error.message || error, \"error\")\n // Revert the DOM change by reloading on error\n window.location.reload()\n } finally {\n pleaseWaitOverlay(false)\n }\n }\n\n updateFolderIcons(fromContainer, toContainer) {\n // Update folder icon for source parent (might now have no children)\n const fromParent = fromContainer.closest(\"alchemy-page-node\")\n fromParent?.updateFolderButton()\n\n // Update folder icon for destination parent (now definitely has children)\n if (fromContainer !== toContainer) {\n const toParent = toContainer.closest(\"alchemy-page-node\")\n toParent?.updateFolderButton()\n }\n }\n}\n\ncustomElements.define(\"alchemy-sitemap\", AlchemySitemap)\n","import Sortable from \"sortablejs\"\nimport { growl } from \"alchemy_admin/growler\"\nimport { post } from \"alchemy_admin/utils/ajax\"\nimport { reloadPreview } from \"alchemy_admin/components/preview_window\"\nimport { dispatchPageDirtyEvent } from \"alchemy_admin/components/element_editor\"\n\nconst SORTABLE_OPTIONS = {\n draggable: \".element-editor\",\n handle: \".element-handle.draggable\",\n ghostClass: \"dragged\",\n animation: 150,\n swapThreshold: 0.65,\n easing: \"cubic-bezier(1, 0, 0, 1)\"\n}\n\nfunction onStart(event) {\n const name = event.item.dataset.elementName\n document\n .querySelectorAll(`[data-droppable-elements~=\"${name}\"]`)\n .forEach((dropzone) => dropzone.classList.add(\"droppable-elements\"))\n}\n\nfunction onSort(event) {\n const item = event.item\n const parentElement = event.to.parentElement.closest(\".element-editor\")\n const params = {\n element_id: item.dataset.elementId,\n position: event.newIndex + 1\n }\n\n if (parentElement) {\n params.parent_element_id = parentElement.dataset.elementId\n }\n\n // Only send the request if the item was moved to a different container\n // or sorted in the same list. Not on the old list in order to avoid incrementing\n // the position of the other elements.\n if (event.target === event.to) {\n post(Alchemy.routes.order_admin_elements_path, params).then((response) => {\n const data = response.data\n growl(data.message)\n if (data.pageHasUnpublishedChanges) {\n dispatchPageDirtyEvent(data)\n }\n reloadPreview()\n item.updateTitle(data.preview_text)\n })\n }\n}\n\nfunction onEnd() {\n const dropzones = document.querySelectorAll(\"[data-droppable-elements]\")\n dropzones.forEach((dropzone) =>\n dropzone.classList.remove(\"droppable-elements\")\n )\n}\n\nclass SortableElements extends HTMLElement {\n connectedCallback() {\n const group = {\n name: this.dataset.elementName,\n put(to, _from, item) {\n return to.el.dataset.droppableElements\n .split(\" \")\n .includes(item.dataset.elementName)\n }\n }\n new Sortable(this, {\n ...SORTABLE_OPTIONS,\n onStart,\n onSort,\n onEnd,\n group\n })\n }\n}\n\ncustomElements.define(\"alchemy-sortable-elements\", SortableElements)\n","import { AlchemyHTMLElement } from \"alchemy_admin/components/alchemy_html_element\"\n\nclass Spinner extends AlchemyHTMLElement {\n static properties = {\n size: { default: \"medium\" },\n color: { default: \"currentColor\" }\n }\n\n render() {\n this.className = `spinner spinner--${this.size}`\n\n return `\n \n \n \n \n \n `\n }\n}\n\ncustomElements.define(\"alchemy-spinner\", Spinner)\n","import { setupSelectLocale } from \"alchemy_admin/i18n\"\n\nclass TagsAutocomplete extends HTMLElement {\n async connectedCallback() {\n await setupSelectLocale()\n\n this.classList.add(\"autocomplete_tag_list\")\n $(this.input).select2(this.select2Config)\n }\n\n get input() {\n return this.getElementsByTagName(\"input\")[0]\n }\n\n get select2Config() {\n return {\n tags: true,\n tokenSeparators: [\",\"],\n openOnEnter: false,\n minimumInputLength: 1,\n createSearchChoice: this.#createSearchChoice,\n ajax: {\n url: this.getAttribute(\"url\"),\n dataType: \"json\",\n data: (term) => {\n return { term }\n },\n results: (data) => {\n return { results: data }\n }\n },\n initSelection: this.#initSelection\n }\n }\n\n #createSearchChoice(term, data) {\n if (\n $(data).filter(function () {\n return this.text.localeCompare(term) === 0\n }).length === 0\n ) {\n return {\n id: term,\n text: term\n }\n }\n }\n\n #initSelection(element, callback) {\n const data = []\n $(element.val().split(\",\")).each(function () {\n data.push({\n id: this.trim(),\n text: this\n })\n })\n callback(data)\n }\n}\n\ncustomElements.define(\"alchemy-tags-autocomplete\", TagsAutocomplete)\n","import \"tinymce\"\nimport { AlchemyHTMLElement } from \"alchemy_admin/components/alchemy_html_element\"\nimport { currentLocale } from \"alchemy_admin/i18n\"\n\nconst DARK_THEME = \"alchemy-dark\"\nconst LIGHT_THEME = \"alchemy\"\n\nclass Tinymce extends AlchemyHTMLElement {\n #min_height = null\n\n /**\n * the observer will initialize Tinymce if the textarea becomes visible\n */\n connected() {\n this.className = \"tinymce_container\"\n\n const observerCallback = (entries, observer) => {\n entries.forEach((entry) => {\n if (entry.intersectionRatio > 0) {\n this._initTinymceEditor()\n // disable observer after the Tinymce was initialized\n observer.unobserve(entry.target)\n }\n })\n }\n\n const options = {\n root: document.getElementById(\"element_area\"),\n rootMargin: \"0px\",\n threshold: [0.05]\n }\n\n this.tinymceIntersectionObserver = new IntersectionObserver(\n observerCallback,\n options\n )\n this.tinymceIntersectionObserver.observe(this)\n\n // Set up theme change listener\n this._setupThemeChangeListener()\n }\n\n /**\n * disconnect intersection observer and remove Tinymce editor if the web components get destroyed\n */\n disconnected() {\n if (this.tinymceIntersectionObserver !== null) {\n this.tinymceIntersectionObserver.disconnect()\n }\n\n // Remove theme change listener\n this._removeThemeChangeListener()\n\n tinymce.get(this.editorId)?.remove(this.editorId)\n }\n\n render() {\n return `\n ${this.initialContent}\n \n `\n }\n\n /**\n * hide the textarea until TinyMCE is ready to show the editor\n */\n afterRender() {\n this.style.minHeight = `${this.minHeight}px`\n this.editor.style.display = \"none\"\n }\n\n /**\n * initialize Richtext area after the Intersection observer triggered\n * @private\n */\n _initTinymceEditor() {\n tinymce.init(this.configuration).then((editors) => {\n editors.forEach((editor) => this._setupEditor(editor))\n })\n }\n\n /**\n * Setup editor after initialization\n * @param {Object} editor - The TinyMCE editor instance\n * @private\n */\n _setupEditor(editor) {\n // mark the editor container as visible\n // without these correction the editor remains hidden\n // after a drag and drop action\n editor.show()\n\n // remove the spinner after the Tinymce initialized (only on first init)\n const spinner = this.getElementsByTagName(\"alchemy-spinner\")[0]\n if (spinner) {\n spinner.remove()\n }\n\n // event listener to mark the editor as dirty\n if (this.elementEditor) {\n editor.on(\"dirty\", (evt) => {\n this.elementEditor.setDirty(evt.target.editorContainer)\n })\n editor.on(\"click\", () => this.elementEditor.onClickElement(false))\n }\n }\n\n /**\n * Set up listener for OS theme changes\n * @private\n */\n _setupThemeChangeListener() {\n this.darkModeMediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\")\n this.themeChangeHandler = (event) => this._handleThemeChange(event)\n this.darkModeMediaQuery.addEventListener(\"change\", this.themeChangeHandler)\n }\n\n /**\n * Remove theme change listener\n * @private\n */\n _removeThemeChangeListener() {\n if (this.darkModeMediaQuery && this.themeChangeHandler) {\n this.darkModeMediaQuery.removeEventListener(\n \"change\",\n this.themeChangeHandler\n )\n }\n }\n\n /**\n * Handle OS theme change and update TinyMCE skin\n * @param {MediaQueryListEvent} event - The media query change event\n * @private\n */\n _handleThemeChange(event) {\n const editor = tinymce.get(this.editorId)\n if (editor) {\n const skin = event.matches ? DARK_THEME : LIGHT_THEME\n const content_css = event.matches ? DARK_THEME : LIGHT_THEME\n\n // Update the skin by reinitializing the editor with new configuration\n editor.remove()\n tinymce\n .init({\n content_css,\n ...this.configuration,\n skin\n })\n .then((editors) => {\n editors.forEach((editor) => this._setupEditor(editor))\n })\n }\n }\n\n get configuration() {\n const customConfig = {}\n\n // read the attributes on the component and add them as custom configuration\n this.getAttributeNames().forEach((attributeName) => {\n if (![\"class\", \"id\", \"is\", \"name\", \"style\"].includes(attributeName)) {\n const config = this.getAttribute(attributeName)\n const key = attributeName.replaceAll(\"-\", \"_\")\n\n // Handle boolean HTML attributes (e.g., readonly=\"readonly\" or readonly=\"\")\n if (config === attributeName || config === \"\") {\n customConfig[key] = true\n } else {\n try {\n customConfig[key] = JSON.parse(config)\n } catch (e) {\n // also string values as parameter\n customConfig[key] = config\n }\n }\n }\n })\n\n const config = {\n content_css: this.preferredTheme,\n ...Alchemy.TinymceDefaults,\n ...customConfig,\n language: currentLocale(),\n selector: `#${this.editorId}`,\n skin: this.preferredTheme\n }\n\n // Tinymce has a height of 400px by default\n // if the element has a min_height set, we use this value for the height as well\n // so we do not need to set both values in the element configuration\n config.height = config.min_height\n\n return config\n }\n\n get preferredTheme() {\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n ? DARK_THEME\n : LIGHT_THEME\n }\n\n get editorId() {\n return this.editor.id\n }\n\n get editor() {\n return this.getElementsByTagName(\"textarea\")[0]\n }\n\n get elementEditor() {\n return document\n .getElementById(this.editorId)\n .closest(\"alchemy-element-editor\")\n }\n\n get minHeight() {\n return this.#min_height || this.configuration.min_height\n }\n\n set minHeight(value) {\n this.#min_height = value\n }\n}\n\ncustomElements.define(\"alchemy-tinymce\", Tinymce)\n","import Spinner from \"alchemy_admin/spinner\"\n\nclass UpdateCheck extends HTMLElement {\n async connectedCallback() {\n const spinner = new Spinner(\"small\")\n spinner.spin(this)\n\n try {\n const response = await fetch(this.url, { credentials: \"include\" })\n const responseJSON = await response.json()\n\n if (response.ok) {\n this.showStatus(responseJSON)\n } else {\n this.showError(response)\n }\n } catch (error) {\n this.showError(error)\n } finally {\n spinner.stop()\n }\n }\n\n get url() {\n return this.getAttribute(\"url\")\n }\n\n showStatus(responseJSON) {\n if (responseJSON[\"status\"] == \"true\") {\n this.querySelector(\".update_available\").classList.remove(\"hidden\")\n } else {\n this.querySelector(\".up_to_date\").classList.remove(\"hidden\")\n }\n }\n\n showError(error) {\n this.querySelector(\".error\").classList.remove(\"hidden\")\n console.error(\"[alchemy] Error fetching update status\", error)\n }\n}\n\ncustomElements.define(\"alchemy-update-check\", UpdateCheck)\n","(()=>{var n=Handlebars.template;(Handlebars.templates=Handlebars.templates||{})[\"node_folder.hbs\"]=n({0:function(n,e,l,a,r){return\"right\"},1:function(n,e,l,a,r){return\"down\"},compiler:[8,\">= 4.3.0\"],main:function(n,e,l,a,r){var o,t=n.lambda,d=n.escapeExpression,u=n.lookupProperty||function(n,e){if(Object.prototype.hasOwnProperty.call(n,e))return n[e]};return'\\n \\n\\n'},useData:!0})})();","import { registerIconLibrary, setDefaultAnimation } from \"shoelace\"\n\n// Change the default animation for all tooltips\nsetDefaultAnimation(\"tooltip.show\", {\n keyframes: [\n { transform: \"translateY(10px)\", opacity: \"0\" },\n { transform: \"translateY(0)\", opacity: \"1\" }\n ],\n options: {\n duration: 100\n }\n})\n\nsetDefaultAnimation(\"tooltip.hide\", {\n keyframes: [\n { transform: \"translateY(0)\", opacity: \"1\" },\n { transform: \"translateY(10px)\", opacity: \"0\" }\n ],\n options: {\n duration: 100\n }\n})\n\n// Change the default animation for all dialogs\nsetDefaultAnimation(\"dialog.show\", {\n keyframes: [\n { transform: \"scale(0.98)\", opacity: \"0\" },\n { transform: \"scale(1)\", opacity: \"1\" }\n ],\n options: {\n duration: 150\n }\n})\n\nsetDefaultAnimation(\"dialog.hide\", {\n keyframes: [\n { transform: \"scale(1)\", opacity: \"1\" },\n { transform: \"scale(0.98)\", opacity: \"0\" }\n ],\n options: {\n duration: 150\n }\n})\n\nconst spriteUrl = document\n .querySelector('link[rel=\"preload\"][as=\"image\"]')\n .getAttribute(\"href\")\n\nconst iconMap = {\n \"x-lg\": \"close\",\n caret: \"arrow-down-s\"\n}\n\nconst options = {\n resolver: (name) => `${spriteUrl}#ri-${iconMap[name] || name}-line`,\n mutator: (svg) => {\n svg.setAttribute(\"fill\", \"currentColor\")\n svg.setAttribute(\"viewBox\", \"0 0 24 24\")\n },\n spriteSheet: true\n}\n\nregisterIconLibrary(\"default\", options)\nregisterIconLibrary(\"system\", options)\n","export function on(eventName, baseSelector, targetSelector, callback) {\n document.querySelectorAll(baseSelector).forEach((baseNode) => {\n baseNode.addEventListener(eventName, (evt) => {\n const targets = Array.from(baseNode.querySelectorAll(targetSelector))\n let currentNode = evt.target\n\n while (currentNode !== baseNode) {\n if (targets.includes(currentNode)) {\n callback.call(currentNode, evt)\n return\n }\n currentNode = currentNode.parentElement\n }\n })\n })\n}\n","import Cropper from \"cropperjs\"\n\nexport default class ImageCropper {\n #initialized = false\n #cropper = null\n #cropFromField = null\n #cropSizeField = null\n\n constructor(image, settings) {\n this.image = image\n this.defaultBox = settings.default_box\n this.aspectRatio = settings.ratio\n this.#cropFromField = document.getElementById(\n settings.crop_from_form_field_id\n )\n this.#cropSizeField = document.getElementById(\n settings.crop_size_form_field_id\n )\n this.elementId = settings.element_id\n this.dialog = Alchemy.currentDialog()\n if (this.dialog) {\n this.dialog.options.closed = () => this.destroy()\n this.bind()\n }\n this.init()\n }\n\n get cropperOptions() {\n return {\n aspectRatio: this.aspectRatio,\n viewMode: 1,\n zoomable: false,\n checkCrossOrigin: false, // Prevent CORS issues\n checkOrientation: false, // Prevent loading the image via AJAX which can cause CORS issues\n data: this.box,\n cropend: () => {\n const data = this.#cropper.getData(true)\n this.update(data)\n }\n }\n }\n\n get cropFrom() {\n if (this.#cropFromField?.value) {\n return this.#cropFromField.value.split(\"x\").map((v) => parseInt(v))\n }\n }\n\n get cropSize() {\n if (this.#cropSizeField?.value) {\n return this.#cropSizeField.value.split(\"x\").map((v) => parseInt(v))\n }\n }\n\n get box() {\n if (this.cropFrom && this.cropSize) {\n return {\n x: this.cropFrom[0],\n y: this.cropFrom[1],\n width: this.cropSize[0],\n height: this.cropSize[1]\n }\n } else {\n return this.defaultBoxSize\n }\n }\n\n get defaultBoxSize() {\n return {\n x: this.defaultBox[0],\n y: this.defaultBox[1],\n width: this.defaultBox[2],\n height: this.defaultBox[3]\n }\n }\n\n init() {\n if (!this.#initialized) {\n this.#cropper = new Cropper(this.image, this.cropperOptions)\n this.#initialized = true\n }\n }\n\n update(coords) {\n this.#cropFromField.value = `${coords.x}x${coords.y}`\n this.#cropFromField.dispatchEvent(new Event(\"change\"))\n this.#cropSizeField.value = `${coords.width}x${coords.height}`\n this.#cropSizeField.dispatchEvent(new Event(\"change\"))\n }\n\n reset() {\n this.#cropper.setData(this.defaultBoxSize)\n this.update(this.defaultBoxSize)\n }\n\n destroy() {\n if (this.#cropper) {\n this.#cropper.destroy()\n }\n this.#initialized = false\n return true\n }\n\n bind() {\n this.dialog.dialog_body.find('button[type=\"submit\"]').on(\"click\", () => {\n const elementEditor = document.querySelector(\n `[data-element-id='${this.elementId}']`\n )\n elementEditor.setDirty()\n this.dialog.close()\n return false\n })\n this.dialog.dialog_body.find('button[type=\"reset\"]').on(\"click\", () => {\n this.reset()\n return false\n })\n }\n}\n","import { Dialog } from \"alchemy_admin/dialog\"\n\nexport default class ImageOverlay extends Dialog {\n constructor(url, options = {}) {\n super(url, options)\n }\n\n init() {\n $(\".zoomed-picture-background\").on(\"click\", (e) => {\n e.stopPropagation()\n if (e.target.nodeName === \"IMG\") {\n return\n }\n this.close()\n return false\n })\n $(\".picture-overlay-handle\").on(\"click\", (e) => {\n this.dialog.toggleClass(\"hide-form\")\n return false\n })\n this.$previous = $(\".previous-picture\")\n this.$next = $(\".next-picture\")\n this.#initKeyboardNavigation()\n super.init()\n }\n\n previous() {\n if (this.$previous[0] != null) {\n this.$previous[0].click()\n }\n }\n\n next() {\n if (this.$next[0] != null) {\n this.$next[0].click()\n }\n }\n\n build() {\n this.dialog_container = $('
    ')\n this.dialog = $('
    ')\n this.dialog_body = $('
    ')\n this.close_button = $(`\n \n `)\n this.dialog.append(this.close_button)\n this.dialog.append(this.dialog_body)\n this.dialog_container.append(this.dialog)\n this.overlay = $('
    ')\n this.$body.append(this.overlay)\n this.$body.append(this.dialog_container)\n }\n\n #initKeyboardNavigation() {\n this.$document.keydown((e) => {\n if (e.target.nodeName === \"INPUT\" || e.target.nodeName === \"TEXTAREA\") {\n return true\n }\n switch (e.which) {\n case 37:\n this.previous()\n return false\n case 39:\n this.next()\n return false\n default:\n return true\n }\n })\n }\n}\n","import { on } from \"alchemy_admin/utils/events\"\nimport { openDialog } from \"alchemy_admin/dialog\"\n\nfunction toggleCheckboxes(state) {\n document\n .querySelectorAll(\".picture_tool.select input[type='checkbox']\")\n .forEach((checkbox) => {\n checkbox.checked = state\n checkbox.closest(\".picture_thumbnail\").classList.toggle(\"active\", state)\n })\n}\n\nfunction checkedInputs() {\n return document.querySelectorAll(\"#picture_archive input:checked\")\n}\n\nfunction editMultiplePicturesUrl(href) {\n const url = new URL(href)\n\n checkedInputs().forEach((entry) =>\n url.searchParams.append(entry.name, entry.value)\n )\n\n return url.toString()\n}\n\n/**\n * Multiple picture select handler for the picture archive.\n */\nexport default function PictureSelector() {\n const selectAllButton = document.querySelector(\"#select_all_pictures\")\n const selectedItemTools = document.querySelector(\".selected_item_tools\")\n\n on(\"click\", \".toolbar_buttons\", \"a#select_all_pictures\", (event) => {\n event.preventDefault()\n\n selectAllButton.classList.toggle(\"active\")\n\n const state = selectAllButton.classList.contains(\"active\")\n\n toggleCheckboxes(state)\n\n selectedItemTools.classList.toggle(\"hidden\", !state)\n })\n\n // make the item toolbar visible and show the checkbox also if it is not hovered anymore\n on(\"change\", \".picture_tool.select\", \"input\", (event) => {\n selectedItemTools.classList.toggle(\"hidden\", checkedInputs().length === 0)\n\n const parentElementClassList = event.target.parentElement.classList\n const checked = event.target.checked\n\n parentElementClassList.toggle(\"visible\", checked)\n })\n\n // open the edit view in a dialog modal\n on(\"click\", \".selected_item_tools\", \"a#edit_multiple_pictures\", (event) => {\n event.preventDefault()\n\n const url = editMultiplePicturesUrl(event.target.href)\n\n openDialog(url, {\n title: event.target.title,\n size: \"400x295\"\n })\n })\n}\n","import Sortable from \"sortablejs\"\nimport { patch } from \"alchemy_admin/utils/ajax\"\nimport { on } from \"alchemy_admin/utils/events\"\nimport { growl } from \"alchemy_admin/growler\"\n\nfunction displayNodeFolders() {\n document.querySelectorAll(\"li.menu-item\").forEach((el) => {\n const leftIconArea = el.querySelector(\".nodes_tree-left_images\")\n const list = el.querySelector(\".children\")\n const node = {\n folded: el.dataset.folded === \"true\",\n id: el.dataset.id,\n type: el.dataset.type\n }\n\n if (list.children.length > 0 || node.folded) {\n leftIconArea.innerHTML = Handlebars.templates[\"node_folder.hbs\"]({\n node: node\n })\n } else {\n leftIconArea.innerHTML = \" \"\n }\n })\n}\n\nfunction onFinishDragging(evt) {\n const url = Alchemy.routes[evt.item.dataset.type].move_api_path(\n evt.item.dataset.id\n )\n const data = {\n target_parent_id: evt.to.dataset.recordId,\n new_position: evt.newIndex\n }\n\n patch(url, data)\n .then(() => {\n const message = Alchemy.t(\"Successfully moved menu item\")\n growl(message)\n displayNodeFolders()\n })\n .catch((error) => {\n growl(error.message || error, \"error\")\n })\n}\n\nfunction handleNodeFolders() {\n on(\"click\", \".nodes_tree\", \".node_folder\", function () {\n const nodeId = this.dataset.recordId\n const menu_item = this.closest(\"li.menu-item\")\n const url =\n Alchemy.routes[this.dataset.recordType].toggle_folded_api_path(nodeId)\n const list = menu_item.querySelector(\".children\")\n\n patch(url)\n .then(() => {\n list.classList.toggle(\"folded\")\n menu_item.dataset.folded =\n menu_item.dataset.folded == \"true\" ? \"false\" : \"true\"\n displayNodeFolders()\n })\n .catch((error) => {\n growl(error.message || error)\n })\n })\n}\n\nexport default function NodeTree() {\n handleNodeFolders()\n displayNodeFolders()\n\n document.querySelectorAll(\".nodes_tree ul.children\").forEach((el) => {\n new Sortable(el, {\n group: \"nodes\",\n animation: 150,\n fallbackOnBody: true,\n swapThreshold: 0.65,\n handle: \".node_name\",\n invertSwap: true,\n onEnd: onFinishDragging\n })\n })\n}\n","// We still use jQuery in some places (ie. select2)\nimport \"handlebars\"\nimport \"jquery\"\nimport \"@ungap/custom-elements\"\nimport { Turbo } from \"@hotwired/turbo-rails\"\nimport \"select2\"\n\nimport Rails from \"@rails/ujs\"\n\nimport { translate } from \"alchemy_admin/i18n\"\nimport { currentDialog, closeCurrentDialog } from \"alchemy_admin/dialog\"\nimport Dirty from \"alchemy_admin/dirty\"\nimport * as FixedElements from \"alchemy_admin/fixed_elements\"\nimport { growl } from \"alchemy_admin/growler\"\nimport Initializer from \"alchemy_admin/initializer\"\nimport { LinkDialog } from \"alchemy_admin/link_dialog\"\nimport pleaseWaitOverlay from \"alchemy_admin/please_wait_overlay\"\nimport Spinner from \"alchemy_admin/spinner\"\nimport { reloadPreview } from \"alchemy_admin/components/preview_window\"\nimport { openConfirmDialog } from \"alchemy_admin/confirm_dialog\"\n\n// Web Components\nimport \"alchemy_admin/components\"\n\n// Handlebars Templates\nimport \"alchemy_admin/templates/compiled\"\n\n// Shoelace Setup\nimport \"alchemy_admin/shoelace_theme\"\n\n// Global Alchemy object\nif (typeof window.Alchemy === \"undefined\") {\n window.Alchemy = {}\n}\n\n// Enhance the global Alchemy object with imported features\nObject.assign(Alchemy, {\n closeCurrentDialog,\n currentDialog,\n ...Dirty,\n t: translate, // Global utility method for translating a given string\n FixedElements,\n growl,\n LinkDialog,\n pleaseWaitOverlay,\n Spinner,\n reloadPreview\n})\n\nRails.start()\nTurbo.config.forms.confirm = openConfirmDialog\ndocument.addEventListener(\"turbo:load\", Initializer)\n\n// Public API for extensions\nexport { RemoteSelect } from \"alchemy_admin/components/remote_select\"\nexport { on } from \"alchemy_admin/utils/events\"\n\n// Page-specific modules - bundled to avoid dual-loading\nexport { default as ImageCropper } from \"alchemy_admin/image_cropper\"\nexport { default as ImageOverlay } from \"alchemy_admin/image_overlay\"\nexport { default as pictureSelector } from \"alchemy_admin/picture_selector\"\nexport { default as NodeTree } from \"alchemy_admin/node_tree\"\n","import Hotkeys from \"alchemy_admin/hotkeys\"\nimport pleaseWaitOverlay from \"alchemy_admin/please_wait_overlay\"\n\nexport default function Initializer() {\n // We obviously have javascript enabled.\n document.documentElement.classList.remove(\"no-js\")\n\n // Initialize hotkeys.\n Hotkeys()\n\n // Add observer for please wait overlay.\n document.querySelectorAll(\".please_wait\").forEach((element) => {\n element.addEventListener(\"click\", pleaseWaitOverlay)\n })\n\n // Hack for enabling tab focus for 's styled as button.\n document.querySelectorAll(\"a.button\").forEach((button) => {\n button.setAttribute(\"tabindex\", 0)\n })\n\n // Override the filter of keymaster.js so we can blur the fields on esc key.\n key.filter = function (event) {\n let tagName = (event.target || event.srcElement).tagName\n return (\n key.isPressed(\"esc\") ||\n !(tagName === \"INPUT\" || tagName === \"SELECT\" || tagName === \"TEXTAREA\")\n )\n }\n}\n"],"names":["KEY_SEPARATOR","getTranslation","key","locale","currentLocale","translations","Alchemy","test","keys","split","group","nestedTranslation","console","warn","document","documentElement","lang","translate","replacement","undefined","translation","replace","async","setupSelectLocale","import","$","extend","fn","select2","defaults","locales","bindedHotkeys","showHelp","evt","target","is","String","fromCharCode","which","openDialog","title","t","size","Hotkeys","scope","jQuery","removeEventListener","addEventListener","forEach","hotkey","unbind","search_fields","querySelectorAll","search_fields_clear","setScope","el","focus","focusVisible","push","click","blur","dataset","alchemyHotkey","createHtmlElement","text","element","createElement","innerHTML","content","children","Spinner$1","constructor","color","this","spinner","spin","parent","body","append","stop","remove","currentDialogs","DEFAULTS","header_height","padding","modal","overflow","ready","closed","Dialog","url","options","$document","$window","window","$body","width","parseInt","height","build","resize","open","dialog","trigger","bind_close_events","requestAnimationFrame","dialog_container","addClass","overlay","load","close","off","removeClass","on","pop","show_spinner","get","data","fail","xhr","show_error","reload","dialog_body","empty","remove_spinner","hide","html","init","dispatchEvent","CustomEvent","bubbles","detail","show","Spinner","watch_remote_forms","$form","event","getResponseHeader","match","responseText","statusText","status","error_body","error_header","error_type","error_messages","$errorDiv","error","close_button","e","keydown","dialog_header","dialog_title","getSize","css","doc_width","doc_height","currentDialog","length","closeCurrentDialog","callback","ConfirmDialog","message","ok_label","cancel_label","on_ok","bindEvents","cancelButton","preventDefault","on_cancel","okButton","source","querySelector","openConfirmDialog","Promise","resolve","pleaseWaitOverlay","checkPageDirtyness","action","find","appendTo","Turbo","visit","pathname","then","proceed","onbeforeunload","Dirty","PageLeaveObserver","currentTarget","removeTab","element_id","fixed_elements","getElementById","panel_name","label","tab","panel","growl","style","flashType","flashNotices","flashMessage","ANCHOR_REGEX","PreviewWindow","HTMLIFrameElement","afterLoad","reloadIcon","loadTimeout","previewReadyHandler","super","handlePreviewReadyMessage","bind","handleEvent","type","clearLoadTimeout","stopSpinner","call","connectedCallback","attachEvents","localStorage","getItem","previewUrlSelect","value","refresh","disconnectedCallback","postMessage","contentWindow","startSpinner","src","setTimeout","isDragged","dragged","transitionProperty","pointerEvents","reloadButton","sizeSelect","setItem","includes","clearTimeout","getAttribute","reloadPreview","customElements","define","extends","IngredientAnchorLink","updateIcon","ingredientId","active","ingredientEditor","setAttribute","Action","HTMLElement","actions","removeFixedElement","updateAnchorIcon","hidePleaseWaitOverlay","func","name","params","hasAttribute","JSON","parse","AlchemyHTMLElement","static","observedAttributes","Object","properties","changeComponent","initialContent","default","getAttributeNames","_updateFromAttribute","_updateComponent","connected","disconnected","attributeChangedCallback","render","afterRender","dispatchCustomEvent","attributeValue","propertyName","reduce","a","b","charAt","toUpperCase","slice","hightlightTerm","term","RegExp","RemoteSelect","allowClear","selection","placeholder","queryParams","input","classList","add","select2Config","onOpen","onChange","removed","added","getElementsByTagName","initSelection","_$el","ajax","ajaxConfig","formatSelection","item","_renderResult","formatResult","_el","query","_renderListEntry","datatype","quietMillis","page","_searchQuery","results","response","_parseResponse","q","name_cont","meta","more","per_page","total_count","Error","_hightlightTerm","attachment","icon_css_class","AutoSubmit","submitEvent","Event","cancelable","form","Button","HTMLButtonElement","remote","stopPropagation","disable","enable","rect","getBoundingClientRect","initialButtonText","removeAttribute","maxChars","formField","getFormField","createDisplayElement","countCharacters","formFields","display","className","after","charLength","textContent","toggle","ClipboardButton","clipboard","ClipboardJS","destroy","formatItem","object","optionEl","swatch","ColorSelect","select","initializeSelect2","toggleColorPicker","val","colorInput","textInput","minimumResultsForSearch","enabled","disabled","inputType","flatpickr","inputField","flatpickrOptions","enableTime","altInput","altFormat","altInputClass","noCalendar","time_24hr","onValueUpdate","_selectedDates","_dateStr","instance","closest","setDirty","dateFormat","DialogLink","HTMLAnchorElement","dialogOptions","contains","JSON_CONTENT_TYPE","TURBO_STREAM_CONTENT_TYPE","isGetRequest","method","toLowerCase","prepareOptions","accept","headers","Accept","getToken","prepareHeaders","stringify","attributes","patch","post","path","fetch","URL","location","origin","search","URLSearchParams","toString","prepareURL","contentType","isJson","isTurboStream","responseData","json","renderStreamMessage","ok","DomIdSelect","dataItem","hash","id","selectElement","pageId","fetchDomIds","routes","api_ingredients_path","page_id","ingredients","filter","ingredient","dom_id","map","prompt","setOptions","reset","frame","elements","contentDocument","Array","from","PublishElementButton","scheduleButtonVariant","scheduleButton","publishButton","dropdown","loading","DeleteElementButton","button","removeElement","elementEditor","fixed","elementId","pageHasUnpublishedChanges","dispatchPageDirtyEvent","tooltip","publishButtonTooltip","ElementEditor","header","toggleButton","focusElement","previewWindow","focusElementPreview","onClickElement","onSaveElement","hasEditors","firstChild","setTitle","selectTabForElement","expand","setClean","warning","ingredientsWithErrors","errorDisplay","errorMessage","appendChild","elementErrors","notice","updateTitle","previewText","ingredientAnchors","anchor","scrollToElement","scrollIntoView","behavior","scroll","reject","tabs","dirty","editor","collapsed","collapse","compact","toggleIcon","collapse_admin_element_path","nestedElementIds","selector","join","nestedElement","catch","finally","expanded","parentElementEditor","expand_admin_element_path","parentElementIds","parentElement","published","isPublished","bodySelector","footer","elementName","hasChildren","option","icon","ElementSelect","dropdownAutoWidth","hint","description","ElementsWindow","visible","turboFrame","focusElementEditor","collapseAllElements","removeProperty","widthFromCookie","setProperty","cookie","collapseButton","row","startsWith","ElementsWindowHandle","dragging","elementsWindow","onMouseDown","onMouseUp","onDrag","pageX","elementWindowWidth","innerWidth","FileEditor","deleteLink","fileIcon","fileName","formFieldId","removeFile","ListFilter","debounceTimer","filterField","clearButton","visibility","debounceTime","clear","matchedItems","itemsToShow","Set","lowerTerm","items","nameAttribute","indexOf","ancestor","itemsSelector","has","block","Message","dismissable","dismiss","iconName","dismissDelay","noticesWrapper","autoDismissDelay","Growl","Icon","spriteUrl","sizeClass","IngredientGroup","HTMLDetailsElement","localStorageKey","isInLocalStorage","expanded_ingredient_groups","localStorageItem","LinkButton","LinkDialog","linkUrl","linkTitle","linkTarget","linkClass","link","setLink","linkButtons","linkUrlField","linkTitleField","linkTargetField","linkClassField","UnlinkButton","linked","isLinked","LinkButtons","removeLink","unlinkButton","setElementDirty","linkButton","formatFileSize","bytes","exponent","Math","floor","log","pow","toFixed","name_or_page_name_cont","node","ancestors","seperator","FileUpload","file","request","progressEventLoaded","progressEventTotal","valid","initialize","_validateFile","_addRequestEventListener","loadedSize","cancel","reader","FileReader","readAsDataURL","image","Image","result","prepend","finished","abort","config","uploader_defaults","maxFileSize","file_size_limit","allowedFiletypes","allowed_filetypes","alchemy_pictures","alchemy_attachments","upload","onprogress","progressEvent","onload","responseMessage","onerror","_errorMessage","errorMessageContainer","progressElement","loaded","total","round","_status","toggleAttribute","_valid","isValid","_value","Progress","buttonLabel","fileUploads","fileCount","handleFileChange","_updateView","actionButton","onComplete","fileUpload","_activeUploads","_setupCloseButton","ariaLabel","_sumFileProgresses","field","accumulator","totalProgress","overallProgressValue","overallUploadSize","every","entry","fileProgress","uploadedFileCount","uploadsStatuses","totalSize","ceil","weight","dropzone","fileInput","_uploadFiles","files","_dragAndDropBehavior","_handleUploadComplete","redirectUrl","uploadProgress","dropzoneElement","isDraggedOver","toggleDropzoneClass","dataTransfer","getAsFile","fileUploadCount","XMLHttpRequest","upload_limit","_submitFile","_createProgress","formData","FormData","set","setRequestHeader","send","removeChild","BUTTON","AlchemyPageNode","folded","folderButton","handleFolderClick","fold_admin_page_path","toggleChildren","updateFolderIcon","childrenContainer","updateFolderButton","folderElement","shouldShowButton","tagName","outerHTML","PagePublicationFields","public_on_picker","public_until_picker","publication_date_fields","public_field","checkbox","now","Date","checked","setDate","pages","site","url_path","language_code","PictureDescriptionSelect","searchParams","PictureEditor","cropFromField","cropSizeField","pictureIdField","targetSizeField","imageCropperField","pictureThumbnail","deleteButton","cropLink","targetSize","pictureId","update","delay","timeout","args","that","apply","debounce","updateImage","updateCropLink","removeImage","observer","MutationObserver","mutationCallback","observe","disconnect","mutationsList","mutation","url_admin_picture_path","crop","imageCropperEnabled","crop_from","cropFrom","crop_size","cropSize","flatten","alt","href","defaultCropFrom","defaultCropSize","mask","n","zoom","imageFileWidth","imageFileHeight","dimensions","imageCropper","PictureThumbnail","start","onLoaded","onError","setImage","createImage","complete","hoist","replaceChildren","PublishPageButton","markDirty","variant","Select","HTMLSelectElement","select2Element","multiple","prev","updateSelect2","selectedValue","Option","hasOwnProperty","AlchemySitemap","searchInput","resultCounter","setupSearch","setupSortables","mutations","addedNodes","nodeType","Node","ELEMENT_NODE","setupSortable","childList","subtree","teardownSearch","handleSearch","handleClearSearch","trim","filterPages","clearFilter","allPages","matchCount","firstMatch","pageElement","container","Sortable","animation","fallbackOnBody","swapThreshold","handle","draggable","onEnd","handleSort","to","oldIndex","newIndex","pageNode","move_admin_page_path","target_parent_id","parentId","new_position","pageData","pageEl","urlPathEl","updateFolderIcons","fromContainer","toContainer","fromParent","toParent","SORTABLE_OPTIONS","ghostClass","easing","onStart","onSort","position","parent_element_id","order_admin_elements_path","preview_text","SortableElements","put","_from","droppableElements","TagsAutocomplete","tags","tokenSeparators","openOnEnter","minimumInputLength","createSearchChoice","dataType","localeCompare","each","DARK_THEME","LIGHT_THEME","min_height","root","rootMargin","threshold","tinymceIntersectionObserver","IntersectionObserver","entries","intersectionRatio","_initTinymceEditor","unobserve","_setupThemeChangeListener","_removeThemeChangeListener","tinymce","editorId","minHeight","configuration","editors","_setupEditor","editorContainer","darkModeMediaQuery","matchMedia","themeChangeHandler","_handleThemeChange","skin","matches","content_css","customConfig","attributeName","replaceAll","preferredTheme","TinymceDefaults","language","UpdateCheck","credentials","responseJSON","showStatus","showError","Handlebars","template","templates","l","r","compiler","main","o","lambda","d","escapeExpression","u","lookupProperty","prototype","nullContext","program","inverse","loc","line","column","end","useData","setDefaultAnimation","keyframes","transform","opacity","duration","iconMap","caret","resolver","mutator","svg","spriteSheet","eventName","baseSelector","targetSelector","baseNode","targets","currentNode","registerIconLibrary","ImageCropper","initialized","cropper","settings","defaultBox","default_box","aspectRatio","ratio","crop_from_form_field_id","crop_size_form_field_id","cropperOptions","viewMode","zoomable","checkCrossOrigin","checkOrientation","box","cropend","getData","v","x","y","defaultBoxSize","Cropper","coords","setData","ImageOverlay","nodeName","toggleClass","$previous","$next","initKeyboardNavigation","previous","next","checkedInputs","PictureSelector","selectAllButton","selectedItemTools","state","toggleCheckboxes","parentElementClassList","editMultiplePicturesUrl","displayNodeFolders","leftIconArea","list","onFinishDragging","move_api_path","recordId","NodeTree","nodeId","menu_item","recordType","toggle_folded_api_path","invertSwap","assign","FixedElements","onCreateLink","link_admin_pages_path","parameterMapping","selected_tab","link_title","link_target","internalForm","attachmentSelect","updatePage","submitForm","linkFormType","internalLink","domIdSelect","linkType","elementAnchor","link_url_regexp","showValidationError","errors","Rails","forms","confirm","srcElement","isPressed"],"mappings":"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"}