Replace custom file-upload-queue.js with FilePond

- Delete file-upload-queue.js (495 lines of custom queue logic)
- Delete sortable.min.js dependency
- Add file-upload-filepond.js: thin wrapper that upgrades .tfe-file-picker
  inputs to FilePond instances with storeAsFile:true for native multipart
  form submission (no form-submit interception needed)
- Update fichiers-fragment.php: replace queue container <ul> elements
  and empty-state <p> with bare <input> elements that FilePond upgrades;
  change name attributes to queue_file[tfe][] etc. for PHP compatibility
- Update add.php, edit.php, partage/index.php: swap JS/CSS refs
- Clean up form.css: remove .fq-* and .tfe-file-queue custom styles,
  add FilePond theme overrides matching xamxam design tokens
- Update dead-code fieldset-files.php for consistency

Server-side stays unchanged: PHP receives ['queue_file']['tfe'][]
exactly as before through native multipart submission.
This commit is contained in:
Pontoporeia
2026-05-10 20:10:15 +02:00
parent 223a15b397
commit 1aff5ff46d
12 changed files with 299 additions and 659 deletions

View File

@@ -8,17 +8,19 @@
* 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 JS queue — client-side, orderable
* 4. Annexes checkbox + JS queue — client-side, orderable
* 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 multi-file JS queue
* - Audio → PeerTube single upload OR multi-file JS queue
* - Vidéo → PeerTube single upload OR FilePond multi-file upload
* - Audio → PeerTube single upload OR FilePond multi-file upload
*
* File queues are managed entirely client-side by file-upload-queue.js.
* This fragment only provides the empty container elements and the file
* picker inputs.
* 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.).
*
* Expected POST:
* formats[] — array of selected format_type IDs
@@ -220,29 +222,25 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
?>
</div>
<!-- ── 3. TFE — multi-file client-side JS queue (always) ── -->
<!-- ── 3. TFE — multi-file upload (FilePond) ── -->
<div class="admin-form-group admin-files-fieldgroup">
<label for="tfe-files-input">TFE<?= !$adminMode ? ' <span class="asterisk">*</span>' : '' ?></label>
<div class="admin-file-input">
<input type="file" id="tfe-files-input"
name="tfe"
name="queue_file[tfe][]"
multiple
accept=".pdf,.jpg,.jpeg,.png,.gif,.webp,.mp4,.webm,.ogv,.mov,.mp3,.ogg,.oga,.wav,.flac,.aac,.m4a,.vtt,.zip,.tar,.gz,.tgz"
class="tfe-file-picker"
<?= !$adminMode ? 'required' : '' ?>>
<progress id="tfe-upload-progress" value="0" max="100" style="display:none;width:100%;margin-top:var(--space-3xs);"></progress>
<small class="admin-file-hint">
PDF (max 100 MB) · Images (JPG/PNG/GIF/WEBP). Glissez pour réordonner.
PDF (max 100 MB) · Images (JPG/PNG/GIF/WEBP) · Vidéo · Audio · VTT · Archives.
Glissez pour réordonner.
PDFs trop lourds ? <a href="https://www.bentopdf.com" target="_blank" rel="noopener">https://bentopdf.com/</a>
</small>
<!-- Queue container — populated by file-upload-queue.js -->
<div id="tfe-file-queue-container" class="fq-container" data-queue-type="tfe">
<ul id="tfe-file-queue" class="tfe-file-queue" aria-label="Fichiers sélectionnés"></ul>
<p id="tfe-file-queue-empty" class="tfe-queue-empty">Aucun fichier sélectionné.</p>
</div>
</div>
</div>
<!-- ── 4. Annexes — multi-file client-side JS queue ── -->
<!-- ── 4. Annexes — multi-file upload (FilePond) ── -->
<div id="annexes-input-block">
<div class="admin-form-group">
<label class="admin-checkbox-label">
@@ -262,19 +260,15 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
<label for="annexe-files-input">Annexes<?= !$adminMode ? ' <span class="asterisk">*</span>' : '' ?></label>
<div class="admin-file-input">
<input type="file" id="annexe-files-input"
name="annexe" multiple
name="queue_file[annexe][]"
multiple
accept=".pdf,.zip,.tar,.gz"
class="tfe-file-picker"
<?= !$adminMode ? 'required' : '' ?>>
<small class="admin-file-hint">PDF ou archives ZIP/TAR. Max 500 MB. Glissez pour réordonner.</small>
<!-- Queue container — populated by file-upload-queue.js -->
<div id="annexe-file-queue-container" class="fq-container" data-queue-type="annexe">
<ul id="annexe-file-queue" class="tfe-file-queue" aria-label="Annexes sélectionnées"></ul>
<p id="annexe-file-queue-empty" class="tfe-queue-empty">Aucun fichier sélectionné.</p>
</div>
</div>
</div>
<script>if(window.XamxamInitQueues)window.XamxamInitQueues();</script>
<script>if(window.XamxamInitFilePonds)window.XamxamInitFilePonds();</script>
<?php endif; ?>
</div>
@@ -309,16 +303,12 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
<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"
name="video"
name="queue_file[video][]"
multiple
accept="video/mp4,video/webm,video/ogg,video/quicktime,.mp4,.webm,.ogv,.mov"
class="tfe-file-picker"
<?= !$adminMode ? 'required' : '' ?>>
<small class="admin-file-hint">MP4, WebM ou MOV. Max 500 MB par fichier. Glissez pour réordonner.</small>
<!-- Queue container — populated by file-upload-queue.js -->
<div id="video-file-queue-container" class="fq-container" data-queue-type="video">
<ul id="video-file-queue" class="tfe-file-queue" aria-label="Fichiers sélectionnés"></ul>
<p id="video-file-queue-empty" class="tfe-queue-empty">Aucun fichier sélectionné.</p>
</div>
<small class="admin-file-hint">MP4, WebM ou MOV. Max 500 MB. Glissez pour réordonner.</small>
</div>
</div>
<?php endif; ?>
@@ -340,27 +330,23 @@ $hasAnnexesChecked = !empty($_POST['has_annexes']);
<label for="audio-files-input">Audio<?= !$adminMode ? ' <span class="asterisk">*</span>' : '' ?></label>
<div class="admin-file-input">
<input type="file" id="audio-files-input"
name="audio"
name="queue_file[audio][]"
multiple
accept="audio/mpeg,audio/ogg,audio/wav,audio/flac,audio/aac,audio/mp4,.mp3,.ogg,.oga,.wav,.flac,.aac,.m4a"
class="tfe-file-picker"
<?= !$adminMode ? 'required' : '' ?>>
<small class="admin-file-hint">MP3, OGG, WAV, FLAC ou AAC. Max 500 MB par fichier. Glissez pour réordonner.</small>
<!-- Queue container — populated by file-upload-queue.js -->
<div id="audio-file-queue-container" class="fq-container" data-queue-type="audio">
<ul id="audio-file-queue" class="tfe-file-queue" aria-label="Fichiers sélectionnés"></ul>
<p id="audio-file-queue-empty" class="tfe-queue-empty">Aucun fichier sélectionné.</p>
</div>
<small class="admin-file-hint">MP3, OGG, WAV, FLAC ou AAC. Max 500 MB. Glissez pour réordonner.</small>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
<script>if(window.XamxamInitQueues)window.XamxamInitQueues();</script>
<script>if(window.XamxamInitFilePonds)window.XamxamInitFilePonds();</script>
</div>
</fieldset><!-- /Fichiers -->
<script>
if(window.XamxamInitFileUploads)window.XamxamInitFileUploads();
if(window.XamxamInitFilePonds)window.XamxamInitFilePonds();
</script>
</div><!-- #format-fichiers-block -->

View File

@@ -375,8 +375,9 @@ function renderShareLinkForm(string $slug, array $link): void
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="<?= App::assetV('/assets/css/common.css') ?>">
<link rel="stylesheet" href="<?= App::assetV('/assets/css/form.css') ?>">
<script src="<?= App::assetV('/assets/js/sortable.min.js') ?>" defer></script>
<script src="<?= App::assetV('/assets/js/file-upload-queue.js') ?>" defer></script>
<link rel="stylesheet" href="<?= App::assetV('/assets/css/filepond.min.css') ?>">
<script src="<?= App::assetV('/assets/js/filepond.min.js') ?>" defer></script>
<script src="<?= App::assetV('/assets/js/file-upload-filepond.js') ?>" defer></script>
<script src="<?= App::assetV('/assets/js/beforeunload-guard.js') ?>" defer></script>
<script src="<?= App::assetV('/assets/js/htmx.min.js') ?>" defer></script>
</head>