mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-23 00:16:23 +00:00
121 lines
3.1 KiB
JavaScript
121 lines
3.1 KiB
JavaScript
|
import { Controller } from "stimulus";
|
||
|
|
||
|
export default class extends Controller {
|
||
|
static targets = ["item", "search", "current"];
|
||
|
|
||
|
connect() {
|
||
|
// TODO: Stimulus >1
|
||
|
this.newArrayValueURL = new URL(window.location.origin);
|
||
|
this.newArrayValueURL.pathname = this.element.dataset.arrayNewArrayValue;
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Al cancelar, se vuelve al estado original de la lista
|
||
|
*/
|
||
|
cancel(event) {
|
||
|
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 = [];
|
||
|
|
||
|
for (const itemTarget of this.itemTargets) {
|
||
|
if (!itemTarget.dataset.value) continue;
|
||
|
if (!this.isChecked(itemTarget)) continue;
|
||
|
|
||
|
this.originalValue.push(itemTarget.dataset.value);
|
||
|
this.newArrayValueURL.searchParams.set("value", itemTarget.dataset.value);
|
||
|
|
||
|
// TODO: Renderizarlas todas juntas
|
||
|
fetch(this.newArrayValueURL)
|
||
|
.then((response) => response.text())
|
||
|
.then((body) =>
|
||
|
this.currentTarget.insertAdjacentHTML("beforeend", body),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// TODO: Stimulus >1
|
||
|
this.element.dataset.arrayOriginalValue = JSON.stringify(
|
||
|
this.originalValue,
|
||
|
);
|
||
|
}
|
||
|
}
|