2024-07-20 18:21:03 +00:00
|
|
|
import { Controller } from "@hotwired/stimulus";
|
2024-05-17 18:24:08 +00:00
|
|
|
|
|
|
|
export default class extends Controller {
|
2024-05-27 19:40:09 +00:00
|
|
|
static targets = ["item", "search", "current", "placeholder"];
|
2024-05-17 18:24:08 +00:00
|
|
|
|
|
|
|
connect() {
|
|
|
|
// TODO: Stimulus >1
|
|
|
|
this.newArrayValueURL = new URL(window.location.origin);
|
2024-10-21 19:16:52 +00:00
|
|
|
|
|
|
|
const [ pathname, search ] = this.element.dataset.arrayNewArrayValue.split("?");
|
|
|
|
|
|
|
|
this.newArrayValueURL.pathname = pathname;
|
|
|
|
this.newArrayValueURL.search = `?${search}`;
|
2024-05-17 18:24:08 +00:00
|
|
|
this.originalValue = JSON.parse(this.element.dataset.arrayOriginalValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Al eliminar el ítem, buscamos por su ID y lo eliminamos del
|
|
|
|
* documento.
|
|
|
|
*/
|
|
|
|
remove(event) {
|
|
|
|
// TODO: Stimulus >1
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
this.itemTargets
|
|
|
|
.find((x) => x.id === event.target.dataset.removeTargetParam)
|
|
|
|
?.remove();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Al buscar, eliminamos las tildes y mayúsculas para no depender de
|
|
|
|
* cómo se escribió.
|
|
|
|
*
|
|
|
|
* Luego buscamos eso en el valor limpio, ignorando los items que ya
|
|
|
|
* están activados.
|
|
|
|
*
|
|
|
|
* Si el término de búsqueda está vacío, volvemos a la lista original.
|
|
|
|
*/
|
|
|
|
search(event) {
|
|
|
|
const needle = this.searchTarget.value
|
|
|
|
.normalize("NFD")
|
|
|
|
.replace(/[\u0300-\u036f]/g, "")
|
|
|
|
.toLowerCase()
|
|
|
|
.trim();
|
|
|
|
|
|
|
|
if (needle) {
|
|
|
|
for (const itemTarget of this.itemTargets) {
|
|
|
|
itemTarget.style.display =
|
|
|
|
itemTarget.querySelector("input")?.checked ||
|
|
|
|
itemTarget.dataset.searchableValue.includes(needle)
|
|
|
|
? ""
|
|
|
|
: "none";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (const itemTarget of this.itemTargets) {
|
|
|
|
itemTarget.style.display = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Obtiene el input de un elemento
|
|
|
|
*
|
|
|
|
* @param [HTMLElement]
|
|
|
|
* @return [HTMLElement,nil]
|
|
|
|
*/
|
|
|
|
inputFrom(target) {
|
|
|
|
if (target.tagName === "INPUT") return target;
|
|
|
|
|
|
|
|
return target.querySelector("input");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Detecta si el item es o contiene un checkbox/radio activado.
|
|
|
|
*
|
|
|
|
* @param [HTMLElement]
|
|
|
|
* @return [Bool]
|
|
|
|
*/
|
|
|
|
isChecked(itemTarget) {
|
|
|
|
return this.inputFrom(itemTarget)?.checked || false;
|
|
|
|
}
|
|
|
|
|
2024-06-05 21:00:55 +00:00
|
|
|
cancelWithEscape(event) {
|
|
|
|
if (event?.key !== "Escape") return;
|
|
|
|
|
|
|
|
this.cancel();
|
|
|
|
}
|
|
|
|
|
2024-05-17 18:24:08 +00:00
|
|
|
/*
|
|
|
|
* Al cancelar, se vuelve al estado original de la lista
|
|
|
|
*/
|
2024-06-05 21:00:55 +00:00
|
|
|
cancel(event = undefined) {
|
2024-05-17 18:24:08 +00:00
|
|
|
for (const itemTarget of this.itemTargets) {
|
|
|
|
const input = this.inputFrom(itemTarget);
|
|
|
|
|
|
|
|
input.checked = this.originalValue.includes(itemTarget.dataset.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Al aceptar, se envía todo el listado de valores nuevos al _backend_
|
|
|
|
* para que devuelva la representación de cada ítem en HTML. Además,
|
|
|
|
* se guarda el nuevo valor como la lista original, para la próxima
|
|
|
|
* cancelación.
|
|
|
|
*/
|
|
|
|
accept(event) {
|
|
|
|
this.currentTarget.innerHTML = "";
|
|
|
|
this.originalValue = [];
|
|
|
|
|
2024-07-10 20:06:29 +00:00
|
|
|
const signal = window.abortController?.signal;
|
|
|
|
|
2024-05-17 18:24:08 +00:00
|
|
|
for (const itemTarget of this.itemTargets) {
|
|
|
|
if (!itemTarget.dataset.value) continue;
|
|
|
|
if (!this.isChecked(itemTarget)) continue;
|
|
|
|
|
|
|
|
this.originalValue.push(itemTarget.dataset.value);
|
2024-07-05 14:56:48 +00:00
|
|
|
this.newArrayValueURL.searchParams.set("value", itemTarget.dataset?.sendValue || itemTarget.dataset?.value);
|
2024-05-17 18:24:08 +00:00
|
|
|
|
2024-05-27 19:40:09 +00:00
|
|
|
const placeholder = this.placeholderTarget.content.firstElementChild.cloneNode(true);
|
|
|
|
|
|
|
|
this.currentTarget.appendChild(placeholder);
|
|
|
|
|
2024-07-10 20:06:29 +00:00
|
|
|
fetch(this.newArrayValueURL, { signal })
|
2024-05-17 18:24:08 +00:00
|
|
|
.then((response) => response.text())
|
2024-05-27 19:40:09 +00:00
|
|
|
.then((body) => {
|
|
|
|
const template = document.createElement("template");
|
|
|
|
template.innerHTML = body;
|
|
|
|
|
|
|
|
placeholder.replaceWith(template.content.firstElementChild);
|
|
|
|
});
|
2024-05-17 18:24:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Stimulus >1
|
|
|
|
this.element.dataset.arrayOriginalValue = JSON.stringify(
|
|
|
|
this.originalValue,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|