127 lines
3.4 KiB
JavaScript
127 lines
3.4 KiB
JavaScript
import { Controller } from "@hotwired/stimulus";
|
|
import Sortable from "sortablejs";
|
|
|
|
export default class extends Controller {
|
|
static targets = [
|
|
"container",
|
|
"input",
|
|
"preview",
|
|
"list",
|
|
"card",
|
|
"checkbox",
|
|
"checkIcon",
|
|
"count",
|
|
];
|
|
|
|
sortable = null;
|
|
|
|
// ------------------------------------------------------------
|
|
// Sélection normale
|
|
// ------------------------------------------------------------
|
|
|
|
cardClick(event) {
|
|
const card = event.currentTarget;
|
|
const checkbox = card.querySelector("input[type='checkbox']");
|
|
checkbox.checked = !checkbox.checked;
|
|
this.updateCard(card, checkbox.checked);
|
|
this.updateCount();
|
|
}
|
|
|
|
toggleCheckbox(event) {
|
|
const checkbox = event.currentTarget;
|
|
const card = checkbox.closest("label");
|
|
this.updateCard(card, checkbox.checked);
|
|
this.updateCount();
|
|
}
|
|
|
|
updateCard(card, checked) {
|
|
const icon = card.querySelector(
|
|
"[data-news--image-selector-target='checkIcon']",
|
|
);
|
|
|
|
const overlay = card.querySelector(
|
|
"[data-news--image-selector-target='overlay']",
|
|
);
|
|
|
|
icon.classList.toggle("hidden", !checked);
|
|
overlay.classList.toggle("hidden", !checked);
|
|
|
|
card.classList.toggle("ring-4", checked);
|
|
card.classList.toggle("ring-amber-500", checked);
|
|
}
|
|
|
|
updateCount() {
|
|
const total = this.checkboxTargets.filter((c) => c.checked).length;
|
|
if (this.hasCountTarget) {
|
|
this.countTarget.textContent = `${total} sélectionnée(s)`;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// Validation → création du preview + activation du drag&drop
|
|
// ------------------------------------------------------------
|
|
|
|
validate() {
|
|
const selected = this.checkboxTargets
|
|
.filter((c) => c.checked)
|
|
.map((c) => c.value);
|
|
|
|
// 🔥 RESET TOTAL DU PREVIEW
|
|
this.previewTarget.innerHTML = "";
|
|
|
|
// 🔁 RECONSTRUCTION À PARTIR DE LA SOURCE DE VÉRITÉ
|
|
selected.forEach((id) => {
|
|
const card = this.cardTargets.find((c) => c.dataset.id === id);
|
|
if (!card) return;
|
|
|
|
const img = document.createElement("img");
|
|
img.src = card.dataset.url;
|
|
img.dataset.id = id;
|
|
img.className = "w-20 h-20 rounded object-cover cursor-move";
|
|
|
|
this.previewTarget.appendChild(img);
|
|
});
|
|
|
|
this.enableSortable();
|
|
this.updateOrder();
|
|
|
|
// ferme la modale
|
|
document.querySelector("[command='close'][commandfor='dialog']").click();
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// SortableJS (drag & drop)
|
|
// ------------------------------------------------------------
|
|
|
|
enableSortable() {
|
|
if (this.sortable) {
|
|
this.sortable.destroy(); // reset si déjà actif
|
|
}
|
|
|
|
this.sortable = Sortable.create(this.previewTarget, {
|
|
animation: 150,
|
|
ghostClass: "opacity-40",
|
|
onSort: () => {
|
|
this.updateOrder();
|
|
},
|
|
});
|
|
}
|
|
|
|
updateOrder() {
|
|
// Supprime les anciennes valeurs
|
|
const container = this.previewTarget.closest("form");
|
|
container
|
|
.querySelectorAll('input[name="selectedImages[]"]')
|
|
.forEach((i) => i.remove());
|
|
|
|
// Crée un input caché par image dans l'ordre
|
|
Array.from(this.previewTarget.children).forEach((img) => {
|
|
const hidden = document.createElement("input");
|
|
hidden.type = "hidden";
|
|
hidden.name = "selectedImages[]";
|
|
hidden.value = img.dataset.id;
|
|
container.appendChild(hidden);
|
|
});
|
|
}
|
|
}
|