Formats activables par evenement + cadre impose exclut strips

- Toggles formats (10x15, 15x20, strip) par evenement
- Strip desactive masque le bouton pellicule sur l'accueil
- Cadre impose/defaut s'applique uniquement sur 10x15 et 15x20 (pas strip)
- Upload cadre evenement le copie dans les deux formats automatiquement
- Section cadres admin simplifiee (un seul bloc au lieu de 3)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 00:45:47 +02:00
parent 77b1127816
commit 6bbcf85e52
5 changed files with 93 additions and 53 deletions

View File

@@ -762,6 +762,12 @@ function afficherDetailEvent(event) {
const select = document.getElementById('admin-media-accueil');
if (event.media_accueil) select.value = event.media_accueil;
});
const fmts = event.formats_actifs || ['10x15', '15x20', 'strip'];
document.getElementById('tog-event-fmt-10x15').checked = fmts.includes('10x15');
document.getElementById('tog-event-fmt-15x20').checked = fmts.includes('15x20');
document.getElementById('tog-event-fmt-strip').checked = fmts.includes('strip');
chargerCadresEvent();
}
@@ -809,12 +815,18 @@ async function uploaderMediaAccueil() {
}
async function sauvegarderEvenement() {
const formats_actifs = [];
if (document.getElementById('tog-event-fmt-10x15').checked) formats_actifs.push('10x15');
if (document.getElementById('tog-event-fmt-15x20').checked) formats_actifs.push('15x20');
if (document.getElementById('tog-event-fmt-strip').checked) formats_actifs.push('strip');
const donnees = {
theme: document.getElementById('admin-theme').value,
nom: getValue('admin-nom-event'),
couleur_primaire: getValue('admin-couleur-primaire'),
couleur_secondaire: getValue('admin-couleur-secondaire'),
media_accueil: getValue('admin-media-accueil') || null,
formats_actifs,
};
if (eventEditId) {
@@ -834,79 +846,88 @@ async function sauvegarderEvenement() {
// === CADRES EVENEMENT ===
const FORMATS_EVENT = ['strip', '10x15', '15x20'];
const FORMATS_CADRE_EVENT = ['10x15', '15x20'];
async function chargerCadresEvent() {
if (!eventEditId) return;
const container = document.getElementById('cadres-event-formats');
container.innerHTML = '';
for (const fmt of FORMATS_EVENT) {
const data = await apiGet(`/api/evenements/${eventEditId}/cadres/${fmt}`);
const section = document.createElement('div');
section.className = 'cadre-event-section';
// Charger cadres du premier format pour afficher le mode + liste
const data = await apiGet(`/api/evenements/${eventEditId}/cadres/15x20`);
const data2 = await apiGet(`/api/evenements/${eventEditId}/cadres/10x15`);
const tous = [...new Set([...(data.disponibles || []), ...(data2.disponibles || [])])];
let cadresHtml = '';
for (const nom of data.disponibles) {
const selected = data.cadre === nom ? ' cadre-selectionne' : '';
cadresHtml += `<div class="cadre-event-item${selected}" onclick="selectionnerCadreEvent('${fmt}','${nom}')">
<img src="/data/evenements/${eventEditId}/cadres/${fmt}/${nom}" alt="${nom}">
<span>${nom.replace('.png','')}</span>
<button class="btn-danger btn-icone" onclick="event.stopPropagation();supprimerCadreEvent('${fmt}','${nom}')">✕</button>
</div>`;
}
section.innerHTML = `
<h4>Format ${fmt}</h4>
<div class="champ">
<label>Mode cadre</label>
<select id="mode-cadre-event-${fmt}" onchange="changerModeCadreEvent('${fmt}')">
<option value="aucun" ${data.mode === 'aucun' ? 'selected' : ''}>Aucun</option>
<option value="disponible" ${data.mode === 'disponible' ? 'selected' : ''}>Disponible (choix utilisateur)</option>
<option value="defaut" ${data.mode === 'defaut' ? 'selected' : ''}>Par defaut (pre-selectionne)</option>
<option value="impose" ${data.mode === 'impose' ? 'selected' : ''}>Impose (toujours applique)</option>
</select>
</div>
<div class="cadres-event-grille">${cadresHtml || '<p class="texte-secondaire">Aucun cadre</p>'}</div>
<input type="file" id="input-cadre-event-${fmt}" accept=".png" class="input-fichier">
<button class="btn-secondaire btn-petit" onclick="uploaderCadreEvent('${fmt}')">Importer cadre ${fmt}</button>
`;
container.appendChild(section);
let cadresHtml = '';
for (const nom of tous) {
const selected = data.cadre === nom ? ' cadre-selectionne' : '';
const src15 = `/data/evenements/${eventEditId}/cadres/15x20/${nom}`;
const src10 = `/data/evenements/${eventEditId}/cadres/10x15/${nom}`;
cadresHtml += `<div class="cadre-event-item${selected}" onclick="selectionnerCadreEvent('${nom}')">
<img src="${src15}" onerror="this.src='${src10}'" alt="${nom}">
<span>${nom.replace('.png','')}</span>
<button class="btn-danger btn-icone" onclick="event.stopPropagation();supprimerCadreEvent('${nom}')">✕</button>
</div>`;
}
container.innerHTML = `
<div class="champ">
<label>Mode cadre</label>
<select id="mode-cadre-event" onchange="changerModeCadreEvent()">
<option value="aucun" ${data.mode === 'aucun' ? 'selected' : ''}>Aucun</option>
<option value="disponible" ${data.mode === 'disponible' ? 'selected' : ''}>Disponible (choix utilisateur)</option>
<option value="defaut" ${data.mode === 'defaut' ? 'selected' : ''}>Par defaut (pre-selectionne)</option>
<option value="impose" ${data.mode === 'impose' ? 'selected' : ''}>Impose (toujours applique)</option>
</select>
</div>
<div class="cadres-event-grille">${cadresHtml || '<p class="texte-secondaire">Aucun cadre importe</p>'}</div>
<input type="file" id="input-cadre-event" accept=".png" class="input-fichier">
<button class="btn-secondaire btn-petit" onclick="uploaderCadreEvent()">Importer cadre</button>
`;
}
async function selectionnerCadreEvent(fmt, nom) {
async function selectionnerCadreEvent(nom) {
if (!eventEditId) return;
const mode = document.getElementById(`mode-cadre-event-${fmt}`).value;
await apiPost(`/api/evenements/${eventEditId}/cadres/${fmt}`, { mode, cadre: nom });
const mode = document.getElementById('mode-cadre-event').value;
for (const fmt of FORMATS_CADRE_EVENT) {
await apiPost(`/api/evenements/${eventEditId}/cadres/${fmt}`, { mode, cadre: nom });
}
await chargerCadresEvent();
}
async function changerModeCadreEvent(fmt) {
async function changerModeCadreEvent() {
if (!eventEditId) return;
const mode = document.getElementById(`mode-cadre-event-${fmt}`).value;
const event = await apiGet(`/api/evenements/${eventEditId}`);
const cadre = (event.cadres || {})[fmt]?.cadre || null;
await apiPost(`/api/evenements/${eventEditId}/cadres/${fmt}`, { mode, cadre });
afficherStatut(`Mode cadre ${fmt} : ${mode}`, 'succes');
const mode = document.getElementById('mode-cadre-event').value;
const ev = await apiGet(`/api/evenements/${eventEditId}`);
const cadre = (ev.cadres || {})['15x20']?.cadre || (ev.cadres || {})['10x15']?.cadre || null;
for (const fmt of FORMATS_CADRE_EVENT) {
await apiPost(`/api/evenements/${eventEditId}/cadres/${fmt}`, { mode, cadre });
}
afficherStatut(`Mode cadre : ${mode}`, 'succes');
}
async function uploaderCadreEvent(fmt) {
async function uploaderCadreEvent() {
if (!eventEditId) return;
const input = document.getElementById(`input-cadre-event-${fmt}`);
const input = document.getElementById('input-cadre-event');
if (!input.files.length) return;
const formData = new FormData();
formData.append('fichier', input.files[0]);
await fetch(`/api/evenements/${eventEditId}/upload-cadre/${fmt}`, { method: 'POST', body: formData });
for (const fmt of FORMATS_CADRE_EVENT) {
const fd = new FormData();
fd.append('fichier', input.files[0]);
await fetch(`/api/evenements/${eventEditId}/upload-cadre/${fmt}`, { method: 'POST', body: fd });
}
input.value = '';
await chargerCadresEvent();
afficherStatut(`Cadre ${fmt} importe`, 'succes');
afficherStatut('Cadre importe (10x15 + 15x20)', 'succes');
}
async function supprimerCadreEvent(fmt, nom) {
async function supprimerCadreEvent(nom) {
if (!eventEditId) return;
await fetch(`/api/evenements/${eventEditId}/cadres/${fmt}/${encodeURIComponent(nom)}`, { method: 'DELETE' });
for (const fmt of FORMATS_CADRE_EVENT) {
await fetch(`/api/evenements/${eventEditId}/cadres/${fmt}/${encodeURIComponent(nom)}`, { method: 'DELETE' }).catch(() => {});
}
await chargerCadresEvent();
afficherStatut('Cadre supprime', 'succes');
}