Add autosave draft system for partage form with HTMX-based session persistence

- New fragment endpoint POST/GET /partage/fragments/draft.php:
  saves all form fields to PHP session, excludes file/csrf/slug fields
  GET returns JSON for JS hydration on page load
  rotates both global CSRF and share CSRF tokens in sync

- form.php accepts optional $formExtraAttrs and $showAutosaveStatus:
  allows injecting HTMX attributes and 'Brouillon enregistré' indicator

- renderShareLinkForm adds hx-post with change/input debounce trigger,
  loads autosave-handler.js, hydrate fields from draft on page load

- Draft cleared on successful form submission in handleShareLinkSubmission

- autosave-handler.js now also updates share_link_token hidden input
  when rotating CSRF token (partage form uses both csrf_token and share_link_token)

- Added .autosave-status CSS to form.css (was admin.css-only)

- Updated fragment routing to accept GET requests (needed for draft hydration)
This commit is contained in:
Pontoporeia
2026-06-11 10:32:53 +02:00
parent 4b37a05be3
commit 99125cc8e3
33 changed files with 1388 additions and 806 deletions

View File

@@ -48,6 +48,10 @@
* ?string $contactPublic — contact visibility flag for edit mode
* ?string $contactInterne — contact email for edit mode
*
* Autosave:
* string $formExtraAttrs — extra HTML attributes to inject into the <form> tag
* bool $showAutosaveStatus — render the "Brouillon enregistré" status indicator
*
* Website:
* string $existingWebsiteUrl
* string $existingWebsiteLabel
@@ -56,6 +60,8 @@
// ── Defaults ──────────────────────────────────────────────────────────────────
$mode = $mode ?? 'add';
$formExtraAttrs = $formExtraAttrs ?? '';
$showAutosaveStatus = $showAutosaveStatus ?? false;
// In admin add/edit, no field is required (admins can save partial records)
$adminMode = ($mode === 'add' || $mode === 'edit');
$formAction = $formAction ?? '';
@@ -146,7 +152,7 @@ $errorFieldName = $errorFieldName ?? null;
<?php endif; ?>
<?php endif; ?>
<form action="<?= $formAction ?>" method="post" enctype="multipart/form-data" class="admin-form" data-beforeunload-guard>
<form action="<?= $formAction ?>" method="post" enctype="multipart/form-data" class="admin-form" data-beforeunload-guard <?= $formExtraAttrs ?>>
<!-- Default: JS-disabled mode (disabled → not submitted → server uses $_FILES path).
On DOMContentLoaded, JS enables this input and sets value="1" → server uses FilePond path. -->
<input type="hidden" name="filepond_mode" value="0" disabled>
@@ -540,6 +546,10 @@ if ($filesMode === 'add'): ?>
</fieldset>
<?php endif; ?>
<?php if ($showAutosaveStatus): ?>
<div class="autosave-status" data-autosave-status></div>
<?php endif; ?>
<div class="form-footer admin-form-footer">
<button type="submit" name="go" class="btn btn--primary"><?= $mode === 'edit' ? 'Enregistrer' : 'Soumettre' ?></button>
<?php if ($mode === 'add' || $mode === 'edit'): ?>