mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-25 09:06:30 +00:00
feat: poder modificar artículos sin salir del formulario principal #16665
This commit is contained in:
parent
2504c13c52
commit
c1096871a6
6 changed files with 131 additions and 7 deletions
|
@ -69,6 +69,30 @@ class PostsController < ApplicationController
|
||||||
render layout: false
|
render layout: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Genera un modal completo
|
||||||
|
#
|
||||||
|
# @todo recibir el atributo anterior
|
||||||
|
# @param :uuid [String] UUID del post (opcional)
|
||||||
|
# @param :layout [String] El layout a cargar (opcional)
|
||||||
|
def modal
|
||||||
|
uuid = pluck_param(:uuid, optional: true)
|
||||||
|
locale
|
||||||
|
|
||||||
|
# @todo hacer que si el uuid no existe se genera un post, para poder
|
||||||
|
# pasar el uuid sabiendolo
|
||||||
|
@post =
|
||||||
|
if uuid.present?
|
||||||
|
site.indexed_posts.find_by!(post_id: uuid).post
|
||||||
|
else
|
||||||
|
# @todo Usar la base de datos
|
||||||
|
site.posts(lang: locale).build(layout: pluck_param(:layout))
|
||||||
|
end
|
||||||
|
|
||||||
|
swap_modals
|
||||||
|
|
||||||
|
render layout: false
|
||||||
|
end
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize Post
|
authorize Post
|
||||||
|
|
||||||
|
@ -158,6 +182,16 @@ class PostsController < ApplicationController
|
||||||
breadcrumb 'posts.edit', ''
|
breadcrumb 'posts.edit', ''
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Este endpoint se encarga de actualizar el post. Si el post se edita
|
||||||
|
# desde el formulario principal, re-renderizamos el formulario si hay
|
||||||
|
# errores o enviamos a otro lado al guardar.
|
||||||
|
#
|
||||||
|
# Si los datos llegaron por HTMX, hay que regenerar el formulario
|
||||||
|
# y reemplazarlo en su modal (?) o responder con su tarjeta para
|
||||||
|
# reemplazarla donde sea que esté.
|
||||||
|
#
|
||||||
|
# @todo la re-renderización del formulario no es necesaria si tenemos
|
||||||
|
# validación client-side.
|
||||||
def update
|
def update
|
||||||
authorize post
|
authorize post
|
||||||
|
|
||||||
|
@ -179,9 +213,20 @@ class PostsController < ApplicationController
|
||||||
|
|
||||||
@value = post.title.value
|
@value = post.title.value
|
||||||
@uuid = post.uuid.value
|
@uuid = post.uuid.value
|
||||||
@name = pluck_param(:name)
|
|
||||||
|
|
||||||
render render_path_from_attribute, layout: false
|
if (result_id = pluck_param(:result_id, optional: true))
|
||||||
|
headers['HX-Retarget'] = "##{result_id}"
|
||||||
|
headers['HX-Reswap'] = 'outerHTML'
|
||||||
|
|
||||||
|
@indexed_post = site.indexed_posts.find_by_post_id(post.uuid.value)
|
||||||
|
|
||||||
|
render 'posts/new_related_post', layout: false
|
||||||
|
# @todo Confirmar que esta ruta no esté transitada
|
||||||
|
else
|
||||||
|
@name = pluck_param(:name)
|
||||||
|
|
||||||
|
render render_path_from_attribute, layout: false
|
||||||
|
end
|
||||||
else
|
else
|
||||||
headers['HX-Retarget'] = "##{params.require(:form)}"
|
headers['HX-Retarget'] = "##{params.require(:form)}"
|
||||||
headers['HX-Reswap'] = 'outerHTML'
|
headers['HX-Reswap'] = 'outerHTML'
|
||||||
|
|
|
@ -37,3 +37,11 @@
|
||||||
|
|
||||||
-# Formularios usados por los modales
|
-# Formularios usados por los modales
|
||||||
= yield(:post_form)
|
= yield(:post_form)
|
||||||
|
|
||||||
|
-#
|
||||||
|
Acumulador de formularios dinámicos, se van cargando a medida que se
|
||||||
|
necesitan en lugar de recursivamente.
|
||||||
|
|
||||||
|
Nunca se eliminan los modales una vez que se cargan para poder tener
|
||||||
|
historial de cambios.
|
||||||
|
%div{ data: { controller: 'htmx', action: 'htmx:getUrl@window->htmx#beforeend' } }
|
||||||
|
|
|
@ -1,16 +1,31 @@
|
||||||
:ruby
|
:ruby
|
||||||
local_assigns[:modal_id] ||= 'generic_modal'
|
|
||||||
|
|
||||||
image = nil
|
image = nil
|
||||||
description = nil
|
description = nil
|
||||||
|
card_id = random_id
|
||||||
|
|
||||||
if post.post.attribute?(:image) && (image = post.post.image.static_file)
|
if post.post.attribute?(:image) && (image = post.post.image.static_file)
|
||||||
description = post.post.image.value['description']
|
description = post.post.image.value['description']
|
||||||
end
|
end
|
||||||
|
|
||||||
.col.mb-3.p-1{ data: { controller: 'modal' } }
|
.col.mb-3.p-1{ id: card_id, data: { controller: 'modal' } }
|
||||||
= render('bootstrap/card', image: image, description: description, title: post.title, class: 'h-100') do
|
= render('bootstrap/card', image: image, description: description, title: post.title, class: 'h-100') do
|
||||||
- if post.post.attribute?(:description)
|
- if post.post.attribute?(:description)
|
||||||
%p.card-text= post.post.description.value
|
%p.card-text= post.post.description.value
|
||||||
|
|
||||||
= render 'bootstrap/btn', content: t('.edit'), data: { action: 'modal#showAnother', 'modal-show-value': local_assigns[:modal_id] }, id: random_id
|
-#
|
||||||
|
Si pasamos el ID del modal, asumimos que hay uno que ya existe y
|
||||||
|
lo llamamos. Sino, tenemos que abrir el modal genérico y cargarle
|
||||||
|
el formulario vía "HTMX".
|
||||||
|
|
||||||
|
- if local_assigns[:modal_id].present?
|
||||||
|
= render 'bootstrap/btn', content: t('.edit'), data: { action: 'modal#showAnother', 'modal-show-value': local_assigns[:modal_id] }, id: random_id
|
||||||
|
- else
|
||||||
|
- form_params = {}
|
||||||
|
- form_params[:layout] = post.layout
|
||||||
|
- form_params[:uuid] = post.post_id
|
||||||
|
- form_params[:modal_id] = form_params[:show] = modal_id = random_id
|
||||||
|
-# Asociar un modal con una tarjeta
|
||||||
|
- form_params[:result_id] = card_id
|
||||||
|
|
||||||
|
-# @todo Poder indicar en qué elemento queremos asociar lo descargado
|
||||||
|
= render 'bootstrap/btn', content: t('.edit'), data: { controller: 'htmx', action: 'modal#showAnother htmx#getUrlOnce', 'modal-show-value': modal_id, 'htmx-get-url-param': site_posts_modal_path(post.site, **form_params) }, id: random_id
|
||||||
|
|
55
app/views/posts/modal.haml
Normal file
55
app/views/posts/modal.haml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
-#
|
||||||
|
|
||||||
|
Genera un modal completo con el formulario del post y sus botones de
|
||||||
|
guardado.
|
||||||
|
|
||||||
|
Se comporta como "HTMX".
|
||||||
|
|
||||||
|
|
||||||
|
:ruby
|
||||||
|
post = @post
|
||||||
|
site = post.site
|
||||||
|
locale = @locale
|
||||||
|
base = random_id
|
||||||
|
dir = t("locales.#{locale}.dir")
|
||||||
|
modal_id = pluck_param(:modal_id)
|
||||||
|
result_id = pluck_param(:result_id)
|
||||||
|
form_id = random_id
|
||||||
|
except = %i[date]
|
||||||
|
options = {
|
||||||
|
id: form_id,
|
||||||
|
multipart: true,
|
||||||
|
class: 'form post'
|
||||||
|
}
|
||||||
|
|
||||||
|
if post.new?
|
||||||
|
url = options[:'hx-post'] = site_posts_path(site, locale: locale)
|
||||||
|
options[:class] += ' new'
|
||||||
|
else
|
||||||
|
url = options[:'hx-patch'] = site_post_path(site, post.id, locale: locale)
|
||||||
|
options[:method] = :patch
|
||||||
|
options[:class] += ' edit'
|
||||||
|
end
|
||||||
|
|
||||||
|
%div{ id: modal_id, data: { controller: 'modal' }}
|
||||||
|
= render 'bootstrap/modal', id: modal_id, modal_content_attributes: { class: 'h-100' } do
|
||||||
|
- content_for :"#{modal_id}_body" do
|
||||||
|
= form_tag url, **options do
|
||||||
|
= hidden_field_tag 'base', base
|
||||||
|
= hidden_field_tag 'result_id', result_id
|
||||||
|
= hidden_field_tag 'modal_id', modal_id
|
||||||
|
= hidden_field_tag "#{base}[layout]", post.layout.name
|
||||||
|
|
||||||
|
= render 'errors', post: post
|
||||||
|
= render 'posts/attributes', site: site, post: post, dir: dir, base: base, locale: locale, except: except
|
||||||
|
-# @todo Volver obligatorios?
|
||||||
|
- except.each do |attr|
|
||||||
|
%input{ type: 'hidden', name: "#{base}[#{attr}]", value: pluck_param(attr, optional: true) }
|
||||||
|
|
||||||
|
- content_for :"#{modal_id}_footer" do
|
||||||
|
-# = render 'posts/validation', site: site, invalid: { id: invalid_id }, submitting: { id: submitting_id }
|
||||||
|
-# = render 'bootstrap/alert', class: 'm-0 d-none fade', id: saved_id, data: { controller: 'notification', action: 'notification:show@window->notification#show', 'notification-hide-class': 'hide', 'notification-show-class': 'show' } do
|
||||||
|
= t('.saved')
|
||||||
|
= render 'bootstrap/btn', form: form_id, content: t('.save'), type: 'submit', class: 'm-0 mt-1 mr-1'
|
||||||
|
= render 'bootstrap/btn', content: t('.close'), action: 'modal#hide', class: 'm-0 mt-1 mr-1'
|
||||||
|
= yield(:post_form)
|
|
@ -1 +1 @@
|
||||||
= render 'posts/new_related_post', post: @indexed_post
|
= render 'posts/new_related_post', post: @indexed_post, modal_id: pluck_param(:modal_id, optional: true)
|
||||||
|
|
|
@ -105,6 +105,7 @@ Rails.application.routes.draw do
|
||||||
get :'posts/new_related_post', to: 'posts#new_related_post'
|
get :'posts/new_related_post', to: 'posts#new_related_post'
|
||||||
get :'posts/new_has_one', to: 'posts#new_has_one'
|
get :'posts/new_has_one', to: 'posts#new_has_one'
|
||||||
get :'posts/form', to: 'posts#form'
|
get :'posts/form', to: 'posts#form'
|
||||||
|
get :'posts/modal', to: 'posts#modal'
|
||||||
|
|
||||||
resources :posts do
|
resources :posts do
|
||||||
get 'p/:page', action: :index, on: :collection
|
get 'p/:page', action: :index, on: :collection
|
||||||
|
|
Loading…
Reference in a new issue