mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-26 08:06:23 +00:00
feat: las notificaciones se manejan con eventos
This commit is contained in:
parent
6f30727a7b
commit
e2af1f215a
7 changed files with 96 additions and 38 deletions
|
@ -3,6 +3,16 @@ import { Controller } from "stimulus";
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = ["invalid", "submitting"];
|
static targets = ["invalid", "submitting"];
|
||||||
|
|
||||||
|
// @todo Stimulus >1
|
||||||
|
get submittingIdValue() {
|
||||||
|
return this.element.dataset?.formValidationSubmittingIdValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo Stimulus >1
|
||||||
|
get invalidIdValue() {
|
||||||
|
return this.element.dataset?.formValidationInvalidIdValue;
|
||||||
|
}
|
||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
this.element.setAttribute("novalidate", true);
|
this.element.setAttribute("novalidate", true);
|
||||||
|
|
||||||
|
@ -19,34 +29,19 @@ export default class extends Controller {
|
||||||
|
|
||||||
submit(event = undefined) {
|
submit(event = undefined) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
event?.stopPropagation();
|
|
||||||
|
|
||||||
if (this.element.reportValidity()) {
|
if (this.element.reportValidity()) {
|
||||||
this.element.classList.remove("was-validated");
|
this.element.classList.remove("was-validated");
|
||||||
this.element.submit();
|
|
||||||
|
|
||||||
this.show(this.submittingTargets);
|
if (!this.element.hasAttribute("hx-post")) this.element.submit();
|
||||||
this.hide(this.invalidTargets);
|
|
||||||
|
window.dispatchEvent(new CustomEvent("notification:show", { detail: { id: this.submittingIdValue } }));
|
||||||
} else {
|
} else {
|
||||||
|
event?.stopPropagation();
|
||||||
|
|
||||||
this.element.classList.add("was-validated");
|
this.element.classList.add("was-validated");
|
||||||
this.hide(this.submittingTargets);
|
|
||||||
this.show(this.invalidTargets);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
show(elements) {
|
window.dispatchEvent(new CustomEvent("notification:show", { detail: { id: this.invalidIdValue } }));
|
||||||
for (const element of elements) {
|
|
||||||
element.classList.remove("d-none");
|
|
||||||
|
|
||||||
setTimeout(() => element.classList.add("show"), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hide(elements) {
|
|
||||||
for (const element of elements) {
|
|
||||||
element.classList.remove("show");
|
|
||||||
|
|
||||||
setTimeout(() => element.classList.add("d-none"), 2000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
43
app/javascript/controllers/notification_controller.js
Normal file
43
app/javascript/controllers/notification_controller.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Solo se puede mostrar una notificación a la vez
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
// @todo Stimulus >1
|
||||||
|
get showClasses() {
|
||||||
|
return (this.element.dataset?.notificationShowClass || "").split(" ").filter(x => x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo Stimulus >1
|
||||||
|
get hideClasses() {
|
||||||
|
return (this.element.dataset?.notificationHideClass || "").split(" ").filter(x => x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Al recibir el evento de mostrar, si no está dirigido al elemento
|
||||||
|
* actual, se oculta.
|
||||||
|
*/
|
||||||
|
show(event = undefined) {
|
||||||
|
if (event?.detail?.id !== this.element.id) {
|
||||||
|
this.hide({ detail: { id: this.element.id } });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.classList.remove("d-none");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.classList.remove(...this.hideClasses);
|
||||||
|
this.element.classList.add(...this.showClasses);
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
hide(event = undefined) {
|
||||||
|
if (event?.detail?.id !== this.element.id) return;
|
||||||
|
|
||||||
|
this.element.classList.remove(...this.showClasses);
|
||||||
|
this.element.classList.add(...this.hideClasses);
|
||||||
|
|
||||||
|
setTimeout(() => this.element.classList.add("d-none"), 150);
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,11 +31,19 @@
|
||||||
end
|
end
|
||||||
|
|
||||||
- dir = t("locales.#{@locale}.dir")
|
- dir = t("locales.#{@locale}.dir")
|
||||||
|
- submitting_id = random_id
|
||||||
|
- invalid_id = random_id
|
||||||
|
- data = {}
|
||||||
|
- data[:controller] = 'unsaved-changes form-validation'
|
||||||
|
- data[:action] = 'unsaved-changes#submit form-validation#submit beforeunload@window->unsaved-changes#unsaved turbolinks:before-visit@window->unsaved-changes#unsavedTurbolinks'
|
||||||
|
- data[:'unsaved-changes-confirm-value'] = t('.confirm')
|
||||||
|
- data[:'form-validation-submitting-id-value'] = submitting_id
|
||||||
|
- data[:'form-validation-invalid-id-value'] = invalid_id
|
||||||
|
|
||||||
-# Comienza el formulario
|
-# Comienza el formulario
|
||||||
= form_tag url, method: method, class: "form post #{extra_class}", multipart: true, data: { controller: 'unsaved-changes form-validation', action: 'unsaved-changes#submit form-validation#submit beforeunload@window->unsaved-changes#unsaved turbolinks:before-visit@window->unsaved-changes#unsavedTurbolinks', 'unsaved-changes-confirm-value': t('.confirm') } do
|
= form_tag url, method: method, class: "form post #{extra_class}", multipart: true, data: data do
|
||||||
-# Botones de guardado
|
-# Botones de guardado
|
||||||
= render 'posts/submit', site: site, post: post
|
= render 'posts/submit', site: site, post: post, invalid: invalid_id, submitting: submitting_id
|
||||||
|
|
||||||
= hidden_field_tag 'post[layout]', post.layout.name
|
= hidden_field_tag 'post[layout]', post.layout.name
|
||||||
|
|
||||||
|
@ -43,7 +51,7 @@
|
||||||
= render 'posts/attributes', site: site, post: post, dir: dir, base: 'post', locale: @locale
|
= render 'posts/attributes', site: site, post: post, dir: dir, base: 'post', locale: @locale
|
||||||
|
|
||||||
-# Botones de guardado
|
-# Botones de guardado
|
||||||
= render 'posts/submit', site: site, post: post
|
= render 'posts/submit', site: site, post: post, invalid: invalid_id, submitting: submitting_id
|
||||||
|
|
||||||
-# Formularios usados por los modales
|
-# Formularios usados por los modales
|
||||||
= yield(:post_form)
|
= yield(:post_form)
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
- invalid_help = site.config.fetch('invalid_help', t('.invalid_help'))
|
|
||||||
- submitting_help = site.config.fetch('submitting_help', t('.submitting_help'))
|
|
||||||
|
|
||||||
.d-flex.flex-column.flex-md-row.align-items-start.mb-3
|
.d-flex.flex-column.flex-md-row.align-items-start.mb-3
|
||||||
%div
|
%div= submit_tag t('.save'), class: 'btn btn-secondary submit-post'
|
||||||
= submit_tag t('.save'), class: 'btn btn-secondary submit-post'
|
= render 'posts/validation', site: site, submitting: { id: submitting }, invalid: { id: invalid }
|
||||||
.d-flex.flex-column.position-relative
|
|
||||||
= render 'bootstrap/alert', class: 'm-0 d-none fade', data: { target: 'form-validation.invalid' } do
|
|
||||||
= invalid_help
|
|
||||||
= render 'bootstrap/alert', class: 'm-0 d-none fade position-absolute top-0 left-0', data: { target: 'form-validation.submitting' } do
|
|
||||||
= submitting_help
|
|
||||||
|
|
16
app/views/posts/_validation.haml
Normal file
16
app/views/posts/_validation.haml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
- invalid = site.config.fetch('invalid', t('.invalid'))
|
||||||
|
- submitting = site.config.fetch('submitting', t('.submitting'))
|
||||||
|
- %i[invalid submitting].each do |key|
|
||||||
|
- local_assigns[key] ||= {}
|
||||||
|
- local_assigns[key][:data] ||= {}
|
||||||
|
- local_assigns[key][:data][:target] ||= "form-validation.#{key}"
|
||||||
|
- local_assigns[key][:data][:action] ||= 'notification:show@window->notification#show'
|
||||||
|
- local_assigns[key][:data][:controller] ||= 'notification'
|
||||||
|
- local_assigns[key][:data][:'notification-hide-class'] ||= 'hide'
|
||||||
|
- local_assigns[key][:data][:'notification-show-class'] ||= 'show'
|
||||||
|
|
||||||
|
.d-flex.flex-column
|
||||||
|
= render 'bootstrap/alert', class: 'm-0 d-none fade', **local_assigns[:invalid] do
|
||||||
|
= invalid
|
||||||
|
= render 'bootstrap/alert', class: 'm-0 d-none fade', **local_assigns[:submitting] do
|
||||||
|
= submitting
|
|
@ -719,8 +719,9 @@ en:
|
||||||
submit:
|
submit:
|
||||||
save: 'Save'
|
save: 'Save'
|
||||||
save_draft: 'Save as draft'
|
save_draft: 'Save as draft'
|
||||||
invalid_help: "Some fields need attention! Please search for the fields marked as not valid."
|
validation:
|
||||||
submitting_help: "Saving changes, please wait..."
|
invalid: "Some fields need attention! Please search for the fields marked as not valid."
|
||||||
|
submitting: "Saving changes, please wait..."
|
||||||
new_array:
|
new_array:
|
||||||
remove: "Remove"
|
remove: "Remove"
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -727,8 +727,9 @@ es:
|
||||||
submit:
|
submit:
|
||||||
save: 'Guardar'
|
save: 'Guardar'
|
||||||
save_draft: 'Guardar como borrador'
|
save_draft: 'Guardar como borrador'
|
||||||
invalid_help: "¡Te falta completar algunos campos! Busca los que estén marcados como no válidos."
|
validation:
|
||||||
submitting_help: "Guardando, por favor espera..."
|
invalid: "¡Te falta completar algunos campos! Busca los que estén marcados como no válidos."
|
||||||
|
submitting: "Guardando, por favor espera..."
|
||||||
new_array:
|
new_array:
|
||||||
remove: "Eliminar"
|
remove: "Eliminar"
|
||||||
attributes:
|
attributes:
|
||||||
|
@ -770,6 +771,8 @@ es:
|
||||||
edit: "Editar"
|
edit: "Editar"
|
||||||
new_predefined_array:
|
new_predefined_array:
|
||||||
edit: "Editar"
|
edit: "Editar"
|
||||||
|
new_predefined_value:
|
||||||
|
edit: "Editar"
|
||||||
new_array:
|
new_array:
|
||||||
edit: "Editar"
|
edit: "Editar"
|
||||||
required: "Seleccioná al menos una opción."
|
required: "Seleccioná al menos una opción."
|
||||||
|
|
Loading…
Reference in a new issue