diff --git a/app/assets/javascripts/alchemy/admin.js b/app/assets/javascripts/alchemy/admin.js
index 597bfed13d..f120a5ccf9 100644
--- a/app/assets/javascripts/alchemy/admin.js
+++ b/app/assets/javascripts/alchemy/admin.js
@@ -9,5 +9,4 @@
//= require alchemy/alchemy.elements_window
//= require alchemy/alchemy.fixed_elements
//= require alchemy/alchemy.image_overlay
-//= require alchemy/alchemy.link_dialog
//= require alchemy/alchemy.preview_window
diff --git a/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee b/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee
deleted file mode 100644
index bcc0144c95..0000000000
--- a/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee
+++ /dev/null
@@ -1,83 +0,0 @@
-# Represents the link Dialog that appears, if a user clicks the link buttons
-# in TinyMCE or on an Ingredient that has links enabled (e.g. Picture)
-#
-class window.Alchemy.LinkDialog extends Alchemy.Dialog
-
- constructor: (link) ->
- url = new URL(Alchemy.routes.link_admin_pages_path, window.location)
- parameterMapping = { url: link.url, selected_tab: link.type, link_title: link.title, link_target: link.target }
-
- # searchParams.set would also add undefined values
- Object.keys(parameterMapping).forEach (key) =>
- url.searchParams.set(key, parameterMapping[key]) if parameterMapping[key]
-
- @options =
- size: '600x320'
- title: 'Link'
- super(url.href, @options)
-
- # Called from Dialog class after the url was loaded
- replace: (data) ->
- # let Dialog class handle the content replacement
- super(data)
- # Store some jQuery objects for further reference
- @$internal_link = $('#internal_link', @dialog_body)
- @$element_anchor = $('#element_anchor', @dialog_body)
- @linkForm = document.querySelector('[data-link-form-type="internal"]')
-
- # attach events we handle
- @attachEvents()
-
- # make the open method a promise
- # maybe in a future version the whole Dialog will respond with a promise result if the dialog is closing
- open: () ->
- super
- new Promise (resolve) =>
- @resolve = resolve
-
- updatePage: (page) ->
- @$internal_link.val(page?.url_path)
- @linkForm.querySelector('alchemy-anchor-select').page = page?.id
-
- # Attaches click events to forms in the link dialog.
- attachEvents: ->
- # enable the dom selection in internal link tab
- @linkForm.addEventListener "Alchemy.PageSelect.ItemRemoved", (e) => @updatePage()
- @linkForm.addEventListener "Alchemy.PageSelect.ItemAdded", (e) => @updatePage(e.detail)
-
- $('[data-link-form-type]', @dialog_body).on "submit", (e) =>
- e.preventDefault()
- @link_type = e.target.dataset.linkFormType
- # get url and remove a possible hash fragment
- url = $("##{@link_type}_link").val().replace(/#\w+$/, '')
- if @link_type == 'internal' && @$element_anchor.val() != ''
- url += "#" + @$element_anchor.val()
-
- # Create the link
- @createLink
- url: url
- title: $("##{@link_type}_link_title").val()
- target: $("##{@link_type}_link_target").val()
- false
-
- # Creates a link if no validation errors are present.
- # Otherwise shows an error notice.
- createLink: (options) ->
- if @link_type == 'external'
- if options.url.match(Alchemy.link_url_regexp)
- @setLink(options)
- else
- return @showValidationError()
- else
- @setLink(options)
- @close()
-
- # Sets the link either in TinyMCE or on an Ingredient.
- setLink: (options) ->
- trimmedUrl = options.url.trim()
- @resolve({url: trimmedUrl, title: options.title, target: options.target, type: @link_type})
-
- # Shows validation errors
- showValidationError: ->
- $('#errors ul', @dialog_body).html("
#{Alchemy.t('url_validation_failed')}")
- $('#errors', @dialog_body).show()
diff --git a/app/javascript/alchemy_admin.js b/app/javascript/alchemy_admin.js
index 37032a17ff..49ca7dda70 100644
--- a/app/javascript/alchemy_admin.js
+++ b/app/javascript/alchemy_admin.js
@@ -11,6 +11,7 @@ import IngredientAnchorLink from "alchemy_admin/ingredient_anchor_link"
import ImageLoader from "alchemy_admin/image_loader"
import ImageCropper from "alchemy_admin/image_cropper"
import Initializer from "alchemy_admin/initializer"
+import { LinkDialog } from "alchemy_admin/link_dialog"
import ListFilter from "alchemy_admin/list_filter"
import pictureSelector from "alchemy_admin/picture_selector"
import pleaseWaitOverlay from "alchemy_admin/please_wait_overlay"
@@ -79,6 +80,7 @@ Object.assign(Alchemy, {
ImageCropper,
Initializer,
IngredientAnchorLink,
+ LinkDialog,
ListFilter,
pictureSelector,
pleaseWaitOverlay,
diff --git a/app/javascript/alchemy_admin/link_dialog.js b/app/javascript/alchemy_admin/link_dialog.js
new file mode 100644
index 0000000000..8d694d7a0e
--- /dev/null
+++ b/app/javascript/alchemy_admin/link_dialog.js
@@ -0,0 +1,118 @@
+// Represents the link Dialog that appears, if a user clicks the link buttons
+// in TinyMCE or on an Ingredient that has links enabled (e.g. Picture)
+//
+export class LinkDialog extends Alchemy.Dialog {
+ constructor(link) {
+ const url = new URL(Alchemy.routes.link_admin_pages_path, window.location)
+ const parameterMapping = {
+ url: link.url,
+ selected_tab: link.type,
+ link_title: link.title,
+ link_target: link.target
+ }
+
+ // searchParams.set would also add undefined values
+ Object.keys(parameterMapping).forEach((key) => {
+ if (parameterMapping[key]) {
+ url.searchParams.set(key, parameterMapping[key])
+ }
+ })
+
+ super(url.href, {
+ size: "600x320",
+ title: "Link"
+ })
+ }
+
+ /**
+ * Called from Dialog class after the url was loaded
+ */
+ replace(data) {
+ // let Dialog class handle the content replacement
+ super.replace(data)
+ // Store some jQuery objects for further reference
+ this.$internal_link = $("#internal_link", this.dialog_body)
+ this.$element_anchor = $("#element_anchor", this.dialog_body)
+ this.linkForm = document.querySelector('[data-link-form-type="internal"]')
+
+ // attach events we handle
+ this.attachEvents()
+ }
+
+ /**
+ * make the open method a promise
+ * maybe in a future version the whole Dialog will respond with a promise result if the dialog is closing
+ * @returns {Promise}
+ */
+ open() {
+ super.open(...arguments)
+ return new Promise((resolve) => (this.resolve = resolve))
+ }
+
+ updatePage(page) {
+ this.$internal_link.val(page != null ? page.url_path : undefined)(
+ (this.linkForm.querySelector("alchemy-anchor-select").page =
+ page != null ? page.id : undefined)
+ )
+ }
+
+ // Attaches click events to forms in the link dialog.
+ attachEvents() {
+ // enable the dom selection in internal link tab
+ this.linkForm.addEventListener("Alchemy.PageSelect.ItemRemoved", (e) =>
+ this.updatePage()
+ )
+ this.linkForm.addEventListener("Alchemy.PageSelect.ItemAdded", (e) =>
+ this.updatePage(e.detail)
+ )
+
+ $("[data-link-form-type]", this.dialog_body).on("submit", (e) => {
+ e.preventDefault()
+ this.link_type = e.target.dataset.linkFormType
+ // get url and remove a possible hash fragment
+ let url = $(`#${this.link_type}_link`).val().replace(/#\w+$/, "")
+ if (this.link_type === "internal" && this.$element_anchor.val() !== "") {
+ url += "#" + this.$element_anchor.val()
+ }
+
+ // Create the link
+ this.createLink({
+ url,
+ title: $(`#${this.link_type}_link_title`).val(),
+ target: $(`#${this.link_type}_link_target`).val()
+ })
+ })
+ }
+
+ // Creates a link if no validation errors are present.
+ // Otherwise shows an error notice.
+ createLink(options) {
+ if (
+ this.link_type === "external" &&
+ !options.url.match(Alchemy.link_url_regexp)
+ ) {
+ this.showValidationError()
+ } else {
+ this.setLink(options)
+ this.close()
+ }
+ }
+
+ // Sets the link either in TinyMCE or on an Ingredient.
+ setLink(options) {
+ this.resolve({
+ url: options.url.trim(),
+ title: options.title,
+ target: options.target,
+ type: this.link_type
+ })
+ }
+
+ // Shows validation errors
+ showValidationError() {
+ $("#errors ul", this.dialog_body).html(
+ `${Alchemy.t("url_validation_failed")}`
+ )
+ return $("#errors", this.dialog_body).show()
+ }
+}