diff --git a/app/controllers/alchemy/admin/elements_controller.rb b/app/controllers/alchemy/admin/elements_controller.rb
index 07bb65576c..3a0669e13d 100644
--- a/app/controllers/alchemy/admin/elements_controller.rb
+++ b/app/controllers/alchemy/admin/elements_controller.rb
@@ -41,12 +41,12 @@ def create
end
end
if @element.save
- render :create
+ render :create, status: :created
else
@element.page_version = @page_version
@elements = @page.available_element_definitions
load_clipboard_items
- render :new
+ render :new, status: :unprocessable_entity
end
end
diff --git a/app/helpers/alchemy/admin/form_helper.rb b/app/helpers/alchemy/admin/form_helper.rb
index 36710fa8e9..80686ec70d 100644
--- a/app/helpers/alchemy/admin/form_helper.rb
+++ b/app/helpers/alchemy/admin/form_helper.rb
@@ -16,7 +16,7 @@ module FormHelper
def alchemy_form_for(object, *args, &block)
options = args.extract_options!
options[:builder] = Alchemy::Forms::Builder
- options[:remote] = request.xhr?
+ options.key?(:remote) || options[:remote] = request.xhr?
options[:html] = {
id: options.delete(:id),
class: ["alchemy", options.delete(:class)].compact.join(" ")
diff --git a/app/javascript/alchemy_admin/components/action.js b/app/javascript/alchemy_admin/components/action.js
index 71c05f2f85..002a07a0c5 100644
--- a/app/javascript/alchemy_admin/components/action.js
+++ b/app/javascript/alchemy_admin/components/action.js
@@ -1,4 +1,5 @@
import { reloadPreview } from "alchemy_admin/components/preview_window"
+import { closeCurrentDialog } from "alchemy_admin/dialog"
import IngredientAnchorLink from "alchemy_admin/ingredient_anchor_link"
class Action extends HTMLElement {
@@ -10,7 +11,7 @@ class Action extends HTMLElement {
// add a intermediate closeCurrentDialog - action
// this will be gone, if all dialogs are working with a promise and
// we don't have to implicitly close the dialog
- closeCurrentDialog: Alchemy.closeCurrentDialog,
+ closeCurrentDialog,
reloadPreview,
updateAnchorIcon: IngredientAnchorLink.updateIcon
}
diff --git a/app/javascript/alchemy_admin/components/element_editor.js b/app/javascript/alchemy_admin/components/element_editor.js
index ca3aa5115b..8aa6fcd361 100644
--- a/app/javascript/alchemy_admin/components/element_editor.js
+++ b/app/javascript/alchemy_admin/components/element_editor.js
@@ -40,6 +40,15 @@ export class ElementEditor extends HTMLElement {
return
}
+ // When newly created, focus the element and refresh the preview
+ if (this.hasAttribute("created")) {
+ this.focusElement()
+ this.previewWindow?.refresh().then(() => {
+ this.focusElementPreview()
+ })
+ this.removeAttribute("created")
+ }
+
// Init GUI elements
ImageLoader.init(this)
fileEditors(
diff --git a/app/javascript/alchemy_admin/dialog.js b/app/javascript/alchemy_admin/dialog.js
index 1d7fbd079d..4fc72cf252 100644
--- a/app/javascript/alchemy_admin/dialog.js
+++ b/app/javascript/alchemy_admin/dialog.js
@@ -124,7 +124,19 @@ export class Dialog {
// Initializes the Dialog body
init() {
+ const turbo_frame = this.dialog_body[0].querySelector("turbo-frame")
+
Hotkeys(this.dialog_body)
+
+ // Re-render dialog body if turbo frame render returned error
+ if (turbo_frame) {
+ turbo_frame.addEventListener("turbo:frame-render", (event) => {
+ if (!event.detail.fetchResponse.ok) {
+ this.watch_remote_forms()
+ }
+ })
+ }
+
this.watch_remote_forms()
}
diff --git a/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb b/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb
index b7dbb2fd3d..d17d5aa764 100644
--- a/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb
+++ b/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb
@@ -3,14 +3,15 @@
(nestable_element = element.nestable_elements.first) &&
Alchemy::Element.all_from_clipboard_for_parent_element(get_clipboard("elements"), element).none?
%>
- <%= form_for [:admin, Alchemy::Element.new(name: nestable_element)],
- remote: true, html: { class: 'add-nested-element-form', id: nil } do |f| %>
- <%= f.hidden_field :name %>
- <%= f.hidden_field :page_version_id, value: element.page_version_id %>
- <%= f.hidden_field :parent_element_id, value: element.id %>
-
+ <%= turbo_frame_tag("new_nested_element_#{element.id}") do %>
+ <%= form_for [:admin, Alchemy::Element.new(name: nestable_element)], html: { class: 'add-nested-element-form', id: nil } do |f| %>
+ <%= f.hidden_field :name %>
+ <%= f.hidden_field :page_version_id, value: element.page_version_id %>
+ <%= f.hidden_field :parent_element_id, value: element.id %>
+
+ <% end %>
<% end %>
<% else %>
<%= link_to_dialog (nestable_element ? Alchemy.t(:add_nested_element, name: Alchemy.t(nestable_element.to_sym, scope: 'element_names')) : Alchemy.t("New Element")),
diff --git a/app/views/alchemy/admin/elements/_clipboard_button.html.erb b/app/views/alchemy/admin/elements/_clipboard_button.html.erb
new file mode 100644
index 0000000000..8b741a5520
--- /dev/null
+++ b/app/views/alchemy/admin/elements/_clipboard_button.html.erb
@@ -0,0 +1,14 @@
+<%= render Alchemy::Admin::ToolbarButton.new(
+ url: alchemy.admin_clipboard_path(remarkable_type: "elements"),
+ label: Alchemy.t("Show clipboard"),
+ icon: :clipboard,
+ icon_style: clipboard_empty?("elements") ? "line" : "fill",
+ dialog_options: {
+ title: Alchemy.t("Clipboard"),
+ size: "400x305"
+ },
+ link_options: {
+ id: "clipboard_button"
+ },
+ if_permitted_to: [:index, :alchemy_admin_clipboard]
+) %>
diff --git a/app/views/alchemy/admin/elements/_element.html.erb b/app/views/alchemy/admin/elements/_element.html.erb
index a624951f7c..0ea1bf4a38 100644
--- a/app/views/alchemy/admin/elements/_element.html.erb
+++ b/app/views/alchemy/admin/elements/_element.html.erb
@@ -4,6 +4,7 @@
data-element-name="<%= element.name %>"
class="<%= element.css_classes.join(" ") %>"
<%= element.compact? ? "compact" : nil %>
+ <%= local_assigns[:created] ? "created" : nil %>
<%= element.fixed? ? "fixed" : nil %>
>
<% unless element.fixed? %>
@@ -68,6 +69,7 @@
<% if element.nestable_elements.any? %>
<%= content_tag :div,
+ id: "element_#{element.id}_nested_elements",
class: "nested-elements", data: {
'droppable-elements' => element.nestable_elements.join(' '),
'element-name' => element.name
diff --git a/app/views/alchemy/admin/elements/_form.html.erb b/app/views/alchemy/admin/elements/_form.html.erb
index 5268717e5f..65f27c4b07 100644
--- a/app/views/alchemy/admin/elements/_form.html.erb
+++ b/app/views/alchemy/admin/elements/_form.html.erb
@@ -3,18 +3,20 @@
<%= Alchemy.t(:no_more_elements_to_add) %>
<% end %>
<%- else -%>
- <%= alchemy_form_for [:admin, @element] do |form| %>
- <%= form.hidden_field :page_version_id %>
- <%= form.input :name,
- label: Alchemy.t(:element_of_type),
- collection: elements_for_select(@elements),
- prompt: Alchemy.t(:select_element),
- selected: (@elements.first if @elements.count == 1),
- input_html: {is: 'alchemy-select', autofocus: true} %>
- <% if @elements.count == 1 %>
- <%= form.hidden_field :name, value: @elements.first[:name] %>
- <% end %>
- <%= form.hidden_field :parent_element_id, value: @parent_element.try(:id) %>
- <%= form.submit Alchemy.t(:add) %>
+ <%= turbo_frame_tag @element do %>
+ <%= alchemy_form_for [:admin, @element], remote: false do |form| %>
+ <%= form.hidden_field :page_version_id %>
+ <%= form.input :name,
+ label: Alchemy.t(:element_of_type),
+ collection: elements_for_select(@elements),
+ prompt: Alchemy.t(:select_element),
+ selected: (@elements.first if @elements.count == 1),
+ input_html: {is: 'alchemy-select', autofocus: true} %>
+ <% if @elements.count == 1 %>
+ <%= form.hidden_field :name, value: @elements.first[:name] %>
+ <% end %>
+ <%= form.hidden_field :parent_element_id, value: @parent_element.try(:id) %>
+ <%= form.submit Alchemy.t(:add) %>
+ <%- end -%>
<%- end -%>
<%- end -%>
diff --git a/app/views/alchemy/admin/elements/create.js.erb b/app/views/alchemy/admin/elements/create.js.erb
deleted file mode 100644
index 28b1222326..0000000000
--- a/app/views/alchemy/admin/elements/create.js.erb
+++ /dev/null
@@ -1,35 +0,0 @@
-(function() {
- var $element_area;
- var element_html = '<%= j render(Alchemy::ElementEditor.new(@element)) %>';
-
-<%- if @cut_element_id -%>
- $('.element-editor[data-element-id="<%= @cut_element_id %>"]').remove();
-<%- end -%>
-
-<% if @element.fixed? %>
- Alchemy.FixedElements.createTab('<%= @element.id %>', '<%= @element.display_name %>');
- $element_area = $('[name="fixed-element-<%= @element.id %>"]');
-<% elsif @element.parent_element %>
- $element_area = $('#element_<%= @element.parent_element_id %> > .nestable-elements > .nested-elements');
-<% else %>
- $element_area = $('#main-content-elements');
-<% end %>
-
-<%- if @insert_at_top -%>
- $element_area.prepend(element_html);
-<%- else -%>
- $element_area.append(element_html);
-<%- end -%>
-
- Alchemy.growl('<%= Alchemy.t(:successfully_added_element) %>');
- Alchemy.closeCurrentDialog();
- Alchemy.reloadPreview();
-
- el = document.querySelector('#element_<%= @element.id %>');
- el.focusElement();
- el.focusElementPreview();
-
-<%- if @clipboard.blank? -%>
- $('#clipboard_button .icon.clipboard').removeClass('full');
-<%- end -%>
-})();
diff --git a/app/views/alchemy/admin/elements/create.turbo_stream.erb b/app/views/alchemy/admin/elements/create.turbo_stream.erb
new file mode 100644
index 0000000000..ba7f0fbfe9
--- /dev/null
+++ b/app/views/alchemy/admin/elements/create.turbo_stream.erb
@@ -0,0 +1,34 @@
+<% opts = {
+ partial: "alchemy/admin/elements/element",
+ locals: {
+ element: Alchemy::ElementEditor.new(@element),
+ created: true
+ }
+} %>
+
+<% if @element.fixed? %>
+ <% target = "fixed_element_#{@element.id}" %>
+<% elsif @element.parent_element %>
+ <% target = "element_#{@element.parent_element_id}_nested_elements" %>
+<% else %>
+ <% target = "main-content-elements" %>
+<% end %>
+
+<%- if @cut_element_id -%>
+ <%= turbo_stream.remove "element_#{@cut_element_id}" %>
+<% end %>
+
+<% if @insert_at_top %>
+ <%= turbo_stream.prepend target, **opts %>
+<% else %>
+ <%= turbo_stream.append target, **opts %>
+<% end %>
+
+<%= turbo_stream.replace "clipboard_button",
+ partial: "alchemy/admin/elements/clipboard_button" %>
+
+
+ <%= Alchemy.t(:successfully_added_element) %>
+
+
+
diff --git a/app/views/alchemy/admin/elements/index.html.erb b/app/views/alchemy/admin/elements/index.html.erb
index a319f19b53..8df6415630 100644
--- a/app/views/alchemy/admin/elements/index.html.erb
+++ b/app/views/alchemy/admin/elements/index.html.erb
@@ -12,20 +12,7 @@
},
if_permitted_to: [:create, Alchemy::Element]
) %>
- <%= render Alchemy::Admin::ToolbarButton.new(
- url: alchemy.admin_clipboard_path(remarkable_type: "elements"),
- label: Alchemy.t("Show clipboard"),
- icon: :clipboard,
- icon_style: clipboard_empty?("elements") ? "line" : "fill",
- dialog_options: {
- title: Alchemy.t("Clipboard"),
- size: "400x305"
- },
- link_options: {
- id: "clipboard_button"
- },
- if_permitted_to: [:index, :alchemy_admin_clipboard]
- ) %>
+ <%= render "alchemy/admin/elements/clipboard_button" %>
" placement="top-end" class="right">