refactor: decouple format extras from main fichiers block, scope FilePond destroy to individual slots, fix FilePond integration for decoupled extras

This commit is contained in:
Pontoporeia
2026-05-10 20:28:24 +02:00
parent 1aff5ff46d
commit ecb559a18a
4 changed files with 105 additions and 67 deletions

View File

@@ -2,25 +2,17 @@
/**
* fichiers-fragment.php (partage & admin)
*
* HTMX fragment: returns the combined Format(s) + Fichiers block.
* Called on every format checkbox change so the Fichiers fieldset adapts.
* Returns the combined Format(s) + Fichiers block.
*
* Fixed inputs (always present in #format-fichiers-block):
* 1. Image de couverture (optional) — single file, plain input
* 2. Note d'intention (PDF, required) — single file, plain input
* 3. TFE — multi-file, FilePond-powered — client-side, orderable
* 4. Annexes checkbox + FilePond-powered queue — client-side, orderable
*
* Format-specific extra inputs (#format-extras-block):
* - Site web → URL field only
* - Vidéo → PeerTube single upload OR FilePond multi-file upload
* - Audio → PeerTube single upload OR FilePond multi-file upload
*
* File uploads are managed by FilePond (file-upload-filepond.js).
* Each .tfe-file-picker input is upgraded to a FilePond instance.
* storeAsFile:true preserves native multipart form submission;
* server receives files via $_FILES indexed by name attribute
* (e.g. queue_file[tfe][], queue_file[video][], etc.).
* Architecture:
* - Formats checkboxes: static, never swapped. They trigger HTMX swaps
* on individual #slot-siteweb, #slot-video, #slot-audio elements.
* - File inputs (couverture, note d'intention, TFE, annexes): always
* static in the DOM — never destroyed by format toggling.
* - Format-specific extras: each is a standalone HTMX fragment slot.
* When unchecked → empty hidden placeholder. When checked → input
* fields rendered via HTMX. This preserves FilePond instances on
* the main file inputs across format changes.
*
* Expected POST:
* formats[] — array of selected format_type IDs
@@ -75,7 +67,7 @@ $hxPost = $adminMode ? '/admin/fichiers-fragment.php' : '/partage/fichiers-fragm
$hasAnnexesChecked = !empty($_POST['has_annexes']);
?>
<!-- ═══════════════════ Format(s) + Fichiers (stable) ═══════════════════ -->
<!-- ═══════════════════ Format(s) + Fichiers (static, never swapped) ═══════════════════ -->
<div id="format-fichiers-block">
<input type="hidden" name="admin_mode" value="<?= $adminMode ? '1' : '0' ?>">
<input type="hidden" name="edit_mode" value="<?= $editMode ? '1' : '0' ?>">
@@ -89,13 +81,7 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
<div>
<span class="admin-row-label">Format(s) du TFE :<?= !$adminMode ? ' <span class="asterisk">*</span>' : '' ?></span>
<fieldset class="admin-checkbox-group"
<?= !$adminMode ? 'required aria-required="true"' : '' ?>
hx-post="<?= htmlspecialchars($hxPost) ?>"
hx-target="#format-fichiers-block"
hx-select="#format-fichiers-block"
hx-trigger="change"
hx-include="this, [name='website_url'], [name='admin_mode'], [name='edit_mode'], [name='_cover'], [name='has_annexes']"
hx-swap="outerHTML">
<?= !$adminMode ? 'required aria-required="true"' : '' ?> >
<legend class="sr-only">Format(s) du TFE</legend>
<ul>
<?php foreach ($allFormats as $opt): ?>
@@ -104,7 +90,28 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
<input type="checkbox"
name="formats[]"
value="<?= htmlspecialchars((string)$opt['id']) ?>"
<?= in_array((int)$opt['id'], $selectedFormats, true) ? 'checked' : '' ?>>
<?= in_array((int)$opt['id'], $selectedFormats, true) ? 'checked' : '' ?>
<?php if ((int)$opt['id'] === ($siteWebId ?? 0)): ?>
hx-post="<?= htmlspecialchars($hxPost) ?>"
hx-target="#slot-siteweb"
hx-select="#slot-siteweb"
hx-trigger="change"
hx-include="[name='formats[]'], [name='website_url'], [name='admin_mode'], [name='edit_mode'], [name='_cover']"
hx-swap="outerHTML"
<?php elseif ((int)$opt['id'] === ($videoId ?? 0)): ?>
hx-post="<?= htmlspecialchars($hxPost) ?>"
hx-target="#slot-video"
hx-select="#slot-video"
hx-trigger="change"
hx-include="[name='formats[]'], [name='website_url'], [name='admin_mode'], [name='edit_mode'], [name='_cover']"
hx-swap="outerHTML"
<?php elseif ((int)$opt['id'] === ($audioId ?? 0)): ?>
hx-post="<?= htmlspecialchars($hxPost) ?>"
hx-target="#slot-audio"
hx-select="#slot-audio"
hx-trigger="change"
hx-include="[name='formats[]'], [name='website_url'], [name='admin_mode'], [name='edit_mode'], [name='_cover']"
<?php endif; ?>>
<?= htmlspecialchars($opt['name']) ?>
</label>
</li>
@@ -272,10 +279,11 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
<?php endif; ?>
</div>
<!-- ── Format-specific extras (swappable) ── -->
<!-- ── Format-specific extras (individual swappable slots) ── -->
<div id="format-extras-block" style="display:flex;flex-direction:column;gap:var(--space-s);">
<!-- Slot: Site web -->
<?php if ($hasSiteWeb): ?>
<div class="admin-form-group">
<div id="slot-siteweb" class="admin-form-group">
<label for="website_url">URL du site<?= !$adminMode ? ' <span class="asterisk">*</span>' : '' ?></label>
<div class="admin-file-input">
<input type="url" id="website_url" name="website_url"
@@ -285,11 +293,14 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
<small>Le TFE sera affiché comme un site embarqué sur sa page publique.</small>
</div>
</div>
<?php else: ?>
<div id="slot-siteweb" hidden></div>
<?php endif; ?>
<!-- Slot: Video -->
<?php if ($hasVideo): ?>
<?php if ($peerTubeEnabled): ?>
<div class="admin-form-group">
<div id="slot-video" class="admin-form-group">
<label for="peertube_video">Vidéo PeerTube<?= !$adminMode ? ' <span class="asterisk">*</span>' : '' ?></label>
<div class="admin-file-input">
<input type="file" id="peertube_video" name="peertube_video"
@@ -299,7 +310,7 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
</div>
</div>
<?php else: ?>
<div class="admin-form-group admin-files-fieldgroup">
<div id="slot-video" class="admin-form-group admin-files-fieldgroup">
<label for="video-files-input">Vidéo<?= !$adminMode ? ' <span class="asterisk">*</span>' : '' ?></label>
<div class="admin-file-input">
<input type="file" id="video-files-input"
@@ -312,11 +323,14 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
</div>
</div>
<?php endif; ?>
<?php else: ?>
<div id="slot-video" hidden></div>
<?php endif; ?>
<!-- Slot: Audio -->
<?php if ($hasAudio): ?>
<?php if ($peerTubeEnabled): ?>
<div class="admin-form-group">
<div id="slot-audio" class="admin-form-group">
<label for="peertube_audio">Audio PeerTube<?= !$adminMode ? ' <span class="asterisk">*</span>' : '' ?></label>
<div class="admin-file-input">
<input type="file" id="peertube_audio" name="peertube_audio"
@@ -326,7 +340,7 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
</div>
</div>
<?php else: ?>
<div class="admin-form-group admin-files-fieldgroup">
<div id="slot-audio" class="admin-form-group admin-files-fieldgroup">
<label for="audio-files-input">Audio<?= !$adminMode ? ' <span class="asterisk">*</span>' : '' ?></label>
<div class="admin-file-input">
<input type="file" id="audio-files-input"
@@ -339,6 +353,8 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
</div>
</div>
<?php endif; ?>
<?php else: ?>
<div id="slot-audio" hidden></div>
<?php endif; ?>
<script>if(window.XamxamInitFilePonds)window.XamxamInitFilePonds();</script>