From 9a9c081cde8a18843c90452df2e23bd974ad2c2c Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Thu, 11 Apr 2024 17:15:52 +0200 Subject: [PATCH] Use turbo frame and stream to create element By responding with a turbo-stream instead of js.erb, we can replace the old Rail-UJS data-remote with a turbo-frame. --- .../alchemy/admin/elements_controller.rb | 4 +-- .../components/element_editor.js | 9 +++++ .../_add_nested_element_form.html.erb | 17 ++++----- .../admin/elements/_clipboard_button.html.erb | 14 ++++++++ .../alchemy/admin/elements/_element.html.erb | 2 ++ .../alchemy/admin/elements/_form.html.erb | 28 ++++++++------- .../alchemy/admin/elements/create.js.erb | 35 ------------------- .../admin/elements/create.turbo_stream.erb | 34 ++++++++++++++++++ .../alchemy/admin/elements/index.html.erb | 17 ++------- .../alchemy/admin/elements_controller_spec.rb | 2 +- 10 files changed, 88 insertions(+), 74 deletions(-) create mode 100644 app/views/alchemy/admin/elements/_clipboard_button.html.erb delete mode 100644 app/views/alchemy/admin/elements/create.js.erb create mode 100644 app/views/alchemy/admin/elements/create.turbo_stream.erb 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/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/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">