// modules/holidays/holidays.js document.addEventListener("DOMContentLoaded", () => { // --- 1. FONCTIONS UTILITAIRES --- /** * Configure les comportements de fermeture d'une modale (Backdrop, Cancel, Escape) */ function setupModal(modalId, openAction = null) { const modal = document.getElementById(modalId); if (!modal) return null; const backdrop = modal.querySelector(".hol-backdrop"); const cancelBtn = modal.querySelector(".hol-cancel"); const close = () => modal.classList.remove("open"); const open = () => { modal.classList.add("open"); if (openAction) openAction(); }; if (backdrop) backdrop.addEventListener("click", close); if (cancelBtn) cancelBtn.addEventListener("click", close); // Fermeture avec ECHAP (uniquement si cette modale est ouverte) document.addEventListener("keydown", (e) => { if (e.key === "Escape" && modal.classList.contains("open")) { close(); } }); return { modal, open, close }; } /** * Échappe les caractères HTML pour éviter les failles XSS simples */ function esc(s) { if (s === null || s === undefined) return ""; return String(s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // --- 2. GESTION MODALE "AJOUTER" --- const addModalCtrl = setupModal("hol-add-modal"); const addBtn = document.getElementById("hol-add-open"); if (addBtn && addModalCtrl) { addBtn.addEventListener("click", addModalCtrl.open); } // --- 3. GESTION MODALE "ÉDITER" --- const editModalCtrl = setupModal("hol-edit-modal"); // Fonction pour charger et ouvrir l'édition via AJAX async function openEditForId(id) { if (!editModalCtrl) return; try { const res = await fetch( `/modules/holidays/view.php?id=${encodeURIComponent(id)}`, { headers: { Accept: "application/json" } }, ); if (!res.ok) throw new Error("Erreur HTTP " + res.status); const it = await res.json(); const modal = editModalCtrl.modal; // Helper pour remplir les champs const setVal = (sel, val) => { const el = modal.querySelector(sel); if (el) el.value = val ?? ""; }; // Remplissage du formulaire setVal("#edit-id", it.id); setVal("#edit-title", it.title); setVal("#edit-country", it.country); setVal("#edit-region", it.region); setVal("#edit-city", it.city); setVal("#edit-lat", it.lat); setVal("#edit-lng", it.lng); setVal("#edit-start", it.desired_start_date); setVal("#edit-end", it.desired_end_date); setVal("#edit-season", it.season_hint); setVal("#edit-days", it.ideal_days); setVal("#edit-status", it.status || "draft"); setVal("#edit-notes", it.notes); editModalCtrl.open(); } catch (err) { console.error(err); alert("Impossible de charger les données de l'idée."); } } // Écouteurs sur les boutons "Éditer" (Liste + Détail) document.body.addEventListener("click", (e) => { // Utilisation de la délégation d'événement pour gérer tous les boutons (même dynamiques) const btn = e.target.closest(".btn-edit"); if (btn && btn.hasAttribute("data-edit-id")) { const id = btn.getAttribute("data-edit-id"); openEditForId(id); } // Cas spécifique du bouton dans le header de la vue détail else if (e.target.id === "hol-edit-open") { const id = e.target.getAttribute("data-edit-id"); openEditForId(id); } }); // --- 4. GESTION SUPPRESSION --- document.body.addEventListener("click", (e) => { const btn = e.target.closest(".btn-delete"); if (btn && btn.hasAttribute("data-del-id")) { const id = btn.getAttribute("data-del-id"); if ( confirm( "Voulez-vous vraiment supprimer cette idée ?\nCette action est irréversible.", ) ) { // Création d'un formulaire temporaire pour le POST const form = document.createElement("form"); form.method = "post"; form.action = "/modules/holidays/save.php"; form.innerHTML = ` `; document.body.appendChild(form); form.submit(); } } }); // --- 5. GÉOCODAGE (Nominatim) --- document.querySelectorAll(".hol-geocode-btn").forEach((btn) => { btn.addEventListener("click", async () => { const scope = btn.getAttribute("data-scope"); // 'add' ou 'edit' let latInput, lngInput, qParts = []; // Récupération des inputs selon le scope if (scope === "edit") { const getVal = (id) => (document.getElementById(id)?.value || "").trim(); qParts = [ getVal("edit-city"), getVal("edit-region"), getVal("edit-country"), ]; latInput = document.getElementById("edit-lat"); lngInput = document.getElementById("edit-lng"); } else { // Scope 'add' : on cherche dans le formulaire parent const form = btn.closest("form"); const getVal = (name) => (form?.querySelector(`input[name="${name}"]`)?.value || "").trim(); qParts = [getVal("city"), getVal("region"), getVal("country")]; latInput = form?.querySelector('input[name="lat"]'); lngInput = form?.querySelector('input[name="lng"]'); } const q = qParts.filter(Boolean).join(", "); if (!q) { alert( "Veuillez renseigner au moins une Ville ou un Pays pour géocoder.", ); return; } // UI : chargement removeNearbyPicker(btn); btn.disabled = true; const originalText = btn.textContent; btn.textContent = "⏳..."; try { const res = await fetch( `/modules/holidays/geocode.php?q=${encodeURIComponent(q)}&limit=5`, { headers: { Accept: "application/json" }, }, ); const data = await res.json(); if (!res.ok) throw new Error(data?.error || "Erreur inconnue"); // Cas 1: Résultat direct (lat/lng uniques) if (data.lat && data.lng) { if (latInput) latInput.value = data.lat; if (lngInput) lngInput.value = data.lng; } // Cas 2: Liste de choix else if (Array.isArray(data.results) && data.results.length > 0) { renderGeocodePicker(btn, data.results, (choice) => { if (latInput) latInput.value = choice.lat; if (lngInput) lngInput.value = choice.lng; removeNearbyPicker(btn); }); } else { alert("Aucun résultat trouvé pour : " + q); } } catch (err) { console.error(err); alert("Erreur lors du géocodage."); } finally { btn.disabled = false; btn.textContent = originalText; } }); }); function renderGeocodePicker(anchorBtn, results, onPick) { removeNearbyPicker(anchorBtn); const wrapper = document.createElement("div"); wrapper.className = "hol-geocode-picker"; // Header const header = document.createElement("div"); header.className = "hol-geocode-picker__header"; header.innerHTML = `Choix multiples`; header .querySelector(".hol-close") .addEventListener("click", () => removeNearbyPicker(anchorBtn)); wrapper.appendChild(header); // Liste const list = document.createElement("ul"); list.className = "hol-geocode-picker__list"; results.forEach((r) => { const li = document.createElement("li"); li.className = "hol-geocode-picker__item"; li.innerHTML = `