mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
Add website-type TFE support: URLs stored as thesis_files rows, HTMX-toggle on Site web format
This commit is contained in:
14
TODO.md
14
TODO.md
@@ -102,6 +102,20 @@
|
||||
- [x] Migration `013_fix_csv_column_shift.sql`: move orientation from synopsis→orientation_id, finality from context_note→finality_id for already-imported theses
|
||||
- [x] Migration `013_fix_remarks_keywords.php`: move keywords from remarks→tags+thesis_tags for already-imported theses
|
||||
|
||||
## Support website-type TFE (URL instead of uploaded files)
|
||||
- [x] Add `file_type = 'website'` support to `thesis_files` — URL stored in `file_path`, no filesystem upload (no schema change needed)
|
||||
- [x] Admin add form: "Site web (URL)" field dynamically shown via HTMX when "Site web" format checked
|
||||
- [x] Admin edit form: website URL field via HTMX toggle + recognize website (🌐 icon) in existing-files list
|
||||
- [x] Student partage form: website URL field via HTMX toggle + HTMX script added
|
||||
- [x] TFE detail page (`tfe.php`): render `website` type as iframe with sandbox in media section
|
||||
- [x] `ThesisCreateController`: handle website URL in submit → `handleWebsiteUrl()` stores as thesis_files row
|
||||
- [x] `ThesisEditController`: handle website URL in save → `handleWebsiteUrl()` replaces existing website row; delete-files skips unlink for URLs
|
||||
- [x] Edit page: website rows deletable via same delete_files checkbox mechanism
|
||||
- [x] File size 0 for website rows — hidden in edit list to avoid showing "0.00 MB"
|
||||
- [x] HTMX fragment endpoint: `/admin/actions/format-website-fragment.php` + `/partage/format-website-fragment`
|
||||
- [x] `checkbox-list.php` partial: optional `hxPost`/`hxTarget` for HTMX live update
|
||||
- [x] Server-side initial render: pre-populate `#website-url-section` if "Site web" already checked
|
||||
|
||||
## Standardise répertoire filter column rendering
|
||||
- [x] Centralise filter column rendering into a shared `repFilterEntry()` function
|
||||
- [x] Define `$filterColumns` config array as single source of truth for the 5 filter columns
|
||||
|
||||
@@ -204,6 +204,11 @@
|
||||
}
|
||||
|
||||
/* ── Jury fieldset ──────────────────────────────────────────────────────── */
|
||||
|
||||
/* ── Website-URL inline fieldset (shown/hidden via HTMX) ────────────────── */
|
||||
/* The fieldset is shown/hidden via outerHTML swap — no CSS needed */
|
||||
|
||||
/* ── Jury fieldset (continued) ──────────────────────────────────────────── */
|
||||
.admin-body fieldset fieldset.admin-jury-lecteurs,
|
||||
.student-body fieldset fieldset.admin-jury-lecteurs {
|
||||
border: none;
|
||||
|
||||
66
app/public/partage/format-website-fragment.php
Normal file
66
app/public/partage/format-website-fragment.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* format-website-fragment.php (partage)
|
||||
*
|
||||
* HTMX fragment for the student share form: returns the website URL input fields
|
||||
* if "Site web" is among the currently selected format checkboxes.
|
||||
*
|
||||
* Regular PHP include inside partage/index.php routing — no separate bootstrap.
|
||||
* The parent partage/index.php already handles boot + session.
|
||||
*
|
||||
* Expected POST:
|
||||
* - formats[]: array of selected format_type IDs
|
||||
* - website_url: current website_url value (for repopulation)
|
||||
* - website_label: current website_label value (for repopulation)
|
||||
*/
|
||||
|
||||
// Find the "Site web" format ID
|
||||
$stmt = Database::getInstance()->getConnection()->prepare(
|
||||
'SELECT id FROM format_types WHERE name = ? LIMIT 1'
|
||||
);
|
||||
$stmt->execute(['Site web']);
|
||||
$websiteFormatId = $stmt->fetchColumn();
|
||||
|
||||
if (!$websiteFormatId) {
|
||||
echo '';
|
||||
exit;
|
||||
}
|
||||
|
||||
$selectedFormats = isset($_POST['formats']) && is_array($_POST['formats'])
|
||||
? array_map('intval', $_POST['formats'])
|
||||
: [];
|
||||
|
||||
if (!in_array((int)$websiteFormatId, $selectedFormats, true)) {
|
||||
echo '';
|
||||
exit;
|
||||
}
|
||||
|
||||
$websiteUrl = htmlspecialchars($_POST['website_url'] ?? '');
|
||||
$websiteLabel = htmlspecialchars($_POST['website_label'] ?? '');
|
||||
?>
|
||||
<fieldset id="website-url-fieldset">
|
||||
<legend>Site web</legend>
|
||||
|
||||
<div class="admin-form-group">
|
||||
<label for="website_url">URL du site :</label>
|
||||
<div class="admin-file-input">
|
||||
<input type="url"
|
||||
id="website_url"
|
||||
name="website_url"
|
||||
value="<?= $websiteUrl ?>"
|
||||
placeholder="https://mon-tfe.erg.be">
|
||||
<small>Si le TFE est un site web, entrez son URL ici. Il sera affiché comme un site embarqué sur la page du TFE.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form-group">
|
||||
<label for="website_label">Légende :</label>
|
||||
<input type="text"
|
||||
id="website_label"
|
||||
name="website_label"
|
||||
value="<?= $websiteLabel ?>"
|
||||
placeholder="Description du site (optionnel)"
|
||||
class="admin-file-label-input"
|
||||
style="max-width:400px;">
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -21,6 +21,13 @@ $parts = explode('/', $path);
|
||||
$slug = $parts[0] ?? '';
|
||||
$action = $parts[1] ?? '';
|
||||
|
||||
// Special route: /partage/format-website-fragment (HTMX fragment, no auth needed)
|
||||
if ($slug === 'format-website-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
App::boot();
|
||||
require_once __DIR__ . '/format-website-fragment.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
// Special route: /partage/recapitulatif?id=N
|
||||
if ($slug === 'recapitulatif' || $slug === 'recapitulatif.php') {
|
||||
App::boot();
|
||||
@@ -265,6 +272,7 @@ function renderShareLinkForm(string $slug, array $link): void
|
||||
<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>
|
||||
<script src="<?= App::assetV('/assets/js/htmx.min.js') ?>" defer></script>
|
||||
</head>
|
||||
<body class="student-body">
|
||||
<main id="main-content">
|
||||
@@ -319,12 +327,6 @@ function renderShareLinkForm(string $slug, array $link): void
|
||||
<?php $name = 'language_autre'; $label = 'Autre(s) langue(s) :'; $value = old($formData, 'language_autre'); $hint = 'Si votre TFE contient une langue absente de la liste, précisez-la ici.'; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
||||
</fieldset>
|
||||
|
||||
<!-- ═══════════════════ Format(s) ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Format(s)</legend>
|
||||
<?php $name = 'formats'; $label = 'Format(s) du TFE :'; $options = $formatTypes; $checked = $formData['formats'] ?? []; $required = true; include APP_ROOT . '/templates/partials/form/checkbox-list.php'; ?>
|
||||
</fieldset>
|
||||
|
||||
<!-- ═══════════════════ Mots-clés ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Mots-clés</legend>
|
||||
@@ -368,6 +370,19 @@ function renderShareLinkForm(string $slug, array $link): void
|
||||
require APP_ROOT . '/templates/partials/form/jury-fieldset.php';
|
||||
?>
|
||||
|
||||
<!-- ═══════════════════ Format(s) ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Format(s)</legend>
|
||||
<?php
|
||||
$name = 'formats'; $label = 'Format(s) du TFE :'; $options = $formatTypes; $checked = $formData['formats'] ?? []; $required = true;
|
||||
$hxPost = '/partage/format-website-fragment';
|
||||
$hxTarget = '#website-url-fieldset';
|
||||
// Capture before include unsets it
|
||||
$_checkedFormatsForSiteWeb = $checked;
|
||||
include APP_ROOT . '/templates/partials/form/checkbox-list.php';
|
||||
?>
|
||||
</fieldset>
|
||||
|
||||
<!-- ═══════════════════ Fichiers ═══════════════════ -->
|
||||
<?php
|
||||
$helpContent = $helpFn('fieldset_files');
|
||||
@@ -375,6 +390,43 @@ function renderShareLinkForm(string $slug, array $link): void
|
||||
include APP_ROOT . '/templates/partials/form/fieldset-files.php';
|
||||
?>
|
||||
|
||||
<!-- Website URL fieldset — shown/hidden via HTMX when "Site web" checked -->
|
||||
<fieldset id="website-url-fieldset" style="display:none">
|
||||
<legend>Site web</legend>
|
||||
|
||||
<div class="admin-form-group">
|
||||
<label for="website_url">URL du site :</label>
|
||||
<div class="admin-file-input">
|
||||
<input type="url"
|
||||
id="website_url"
|
||||
name="website_url"
|
||||
value="<?= htmlspecialchars($formData['website_url'] ?? '') ?>"
|
||||
placeholder="https://mon-tfe.erg.be">
|
||||
<small>Si le TFE est un site web, entrez son URL ici. Il sera affiché comme un site embarqué sur la page du TFE.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form-group">
|
||||
<label for="website_label">Légende :</label>
|
||||
<input type="text"
|
||||
id="website_label"
|
||||
name="website_label"
|
||||
value="<?= htmlspecialchars($formData['website_label'] ?? '') ?>"
|
||||
placeholder="Description du site (optionnel)"
|
||||
class="admin-file-label-input"
|
||||
style="max-width:400px;">
|
||||
</div>
|
||||
</fieldset>
|
||||
<?php
|
||||
// Server-side: show if Site web already checked (e.g. on error redirect)
|
||||
$_stmt = Database::getInstance()->getConnection()->prepare('SELECT id FROM format_types WHERE name = ? LIMIT 1');
|
||||
$_stmt->execute(['Site web']);
|
||||
$_siteWebId = $_stmt->fetchColumn();
|
||||
if ($_siteWebId && in_array((string)$_siteWebId, array_map('strval', $_checkedFormatsForSiteWeb), true)) {
|
||||
echo '<script>document.getElementById("website-url-fieldset").style.display=""</script>';
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- ═══════════════════ Métadonnées complémentaires ═══════════════════ -->
|
||||
<?php
|
||||
$oldFn = $shareOldFn;
|
||||
|
||||
@@ -216,6 +216,9 @@ class ThesisCreateController
|
||||
$this->db->handleBannerUpload($thesisId, $files['banner'] ?? null);
|
||||
$this->handleThesisFiles($thesisId, $data['annee'], $identifier, $files['files'] ?? null, $authorSlug, $post);
|
||||
|
||||
// ── 6. Website URL — stored as thesis_files row ──────────────────────
|
||||
$this->handleWebsiteUrl($thesisId, $post);
|
||||
|
||||
return $thesisId;
|
||||
}
|
||||
|
||||
@@ -813,4 +816,41 @@ class ThesisCreateController
|
||||
}
|
||||
return $candidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a website URL as a thesis_files row (file_type = 'website').
|
||||
*
|
||||
* The URL is stored in file_path; no filesystem operation is performed.
|
||||
* label and sort_order from the POST are preserved.
|
||||
*/
|
||||
private function handleWebsiteUrl(int $thesisId, array $post): void
|
||||
{
|
||||
$websiteUrl = trim($post['website_url'] ?? '');
|
||||
if ($websiteUrl === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate URL
|
||||
$websiteUrl = filter_var($websiteUrl, FILTER_VALIDATE_URL);
|
||||
if ($websiteUrl === false) {
|
||||
error_log('ThesisCreateController: invalid website URL, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
$label = trim($post['website_label'] ?? '');
|
||||
$sortOrder = isset($post['website_order']) ? (int)$post['website_order'] : null;
|
||||
$fileName = rtrim(preg_replace('#^https?://#i', '', $websiteUrl), '/');
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId,
|
||||
'website',
|
||||
$websiteUrl,
|
||||
$fileName,
|
||||
0,
|
||||
'text/html',
|
||||
$label !== '' ? $label : null,
|
||||
$sortOrder
|
||||
);
|
||||
error_log("ThesisCreateController: website stored → $websiteUrl");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,9 +331,12 @@ class ThesisEditController
|
||||
}
|
||||
$filePath = $this->db->deleteThesisFile($fileId, $thesisId);
|
||||
if ($filePath && defined('STORAGE_ROOT')) {
|
||||
$abs = STORAGE_ROOT . '/' . $filePath;
|
||||
if (file_exists($abs)) {
|
||||
@unlink($abs);
|
||||
// Skip filesystem deletion for website URLs (not real files)
|
||||
if (!str_starts_with($filePath, 'http://') && !str_starts_with($filePath, 'https://')) {
|
||||
$abs = STORAGE_ROOT . '/' . $filePath;
|
||||
if (file_exists($abs)) {
|
||||
@unlink($abs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,6 +361,9 @@ class ThesisEditController
|
||||
if (!empty($files['files']['name'][0])) {
|
||||
$this->handleThesisFiles($thesisId, $post, $files['files']);
|
||||
}
|
||||
|
||||
// ── Website URL — add or update ──────────────────────────────────────
|
||||
$this->handleWebsiteUrl($thesisId, $post);
|
||||
}
|
||||
|
||||
// ── Private: file uploads ─────────────────────────────────────────────────
|
||||
@@ -703,4 +709,50 @@ class ThesisEditController
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or update a website URL thesis_file row.
|
||||
*
|
||||
* If a website row already exists for this thesis, it is replaced.
|
||||
* Otherwise a new row is inserted.
|
||||
*/
|
||||
private function handleWebsiteUrl(int $thesisId, array $post): void
|
||||
{
|
||||
$websiteUrl = trim($post['website_url'] ?? '');
|
||||
|
||||
// Remove existing website rows
|
||||
$existingFiles = $this->db->getThesisFiles($thesisId);
|
||||
foreach ($existingFiles as $f) {
|
||||
if ($f['file_type'] === 'website') {
|
||||
$this->db->deleteThesisFile((int)$f['id'], $thesisId);
|
||||
}
|
||||
}
|
||||
|
||||
if ($websiteUrl === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate URL
|
||||
$websiteUrl = filter_var($websiteUrl, FILTER_VALIDATE_URL);
|
||||
if ($websiteUrl === false) {
|
||||
error_log('ThesisEditController: invalid website URL, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
$label = trim($post['website_label'] ?? '');
|
||||
$sortOrder = isset($post['website_order']) ? (int)$post['website_order'] : null;
|
||||
$fileName = rtrim(preg_replace('#^https?://#i', '', $websiteUrl), '/');
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId,
|
||||
'website',
|
||||
$websiteUrl,
|
||||
$fileName,
|
||||
0,
|
||||
'text/html',
|
||||
$label !== '' ? $label : null,
|
||||
$sortOrder
|
||||
);
|
||||
error_log("ThesisEditController: website stored → $websiteUrl");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,12 +36,6 @@
|
||||
<?php $name = 'language_autre'; $label = 'Autre(s) langue(s) :'; $value = old('language_autre'); $hint = 'Si votre TFE contient une langue absente de la liste, précisez-la ici.'; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
||||
</fieldset>
|
||||
|
||||
<!-- ═══════════════════ Format(s) ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Format(s)</legend>
|
||||
<?php $name = 'formats'; $label = 'Format(s) du TFE :'; $options = $formatTypes; $checked = $formData['formats'] ?? []; $required = true; include APP_ROOT . '/templates/partials/form/checkbox-list.php'; ?>
|
||||
</fieldset>
|
||||
|
||||
<!-- ═══════════════════ Mots-clés ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Mots-clés</legend>
|
||||
@@ -74,9 +68,59 @@
|
||||
require APP_ROOT . '/templates/partials/form/jury-fieldset.php';
|
||||
?>
|
||||
|
||||
<!-- ═══════════════════ Format(s) ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Format(s)</legend>
|
||||
<?php
|
||||
$name = 'formats'; $label = 'Format(s) du TFE :'; $options = $formatTypes; $checked = $formData['formats'] ?? []; $required = true;
|
||||
$hxPost = '/partage/format-website-fragment';
|
||||
$hxTarget = '#website-url-fieldset';
|
||||
// Capture before include unsets it
|
||||
$_checkedFormatsForSiteWeb = $checked;
|
||||
include APP_ROOT . '/templates/partials/form/checkbox-list.php';
|
||||
?>
|
||||
</fieldset>
|
||||
|
||||
<!-- ═══════════════════ Fichiers ═══════════════════ -->
|
||||
<?php include APP_ROOT . '/templates/partials/form/fieldset-files.php'; ?>
|
||||
|
||||
<!-- Website URL fieldset — shown/hidden via HTMX when "Site web" checked -->
|
||||
<fieldset id="website-url-fieldset" style="display:none">
|
||||
<legend>Site web</legend>
|
||||
|
||||
<div class="admin-form-group">
|
||||
<label for="website_url">URL du site :</label>
|
||||
<div class="admin-file-input">
|
||||
<input type="url"
|
||||
id="website_url"
|
||||
name="website_url"
|
||||
value="<?= htmlspecialchars($formData['website_url'] ?? '') ?>"
|
||||
placeholder="https://mon-tfe.erg.be">
|
||||
<small>Si le TFE est un site web, entrez son URL ici. Il sera affiché comme un site embarqué sur la page du TFE.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form-group">
|
||||
<label for="website_label">Légende :</label>
|
||||
<input type="text"
|
||||
id="website_label"
|
||||
name="website_label"
|
||||
value="<?= htmlspecialchars($formData['website_label'] ?? '') ?>"
|
||||
placeholder="Description du site (optionnel)"
|
||||
class="admin-file-label-input"
|
||||
style="max-width:400px;">
|
||||
</div>
|
||||
</fieldset>
|
||||
<?php
|
||||
// Server-side: show if Site web already checked (e.g. on error redirect)
|
||||
$_stmt = Database::getInstance()->getConnection()->prepare('SELECT id FROM format_types WHERE name = ? LIMIT 1');
|
||||
$_stmt->execute(['Site web']);
|
||||
$_siteWebId = $_stmt->fetchColumn();
|
||||
if ($_siteWebId && in_array((string)$_siteWebId, array_map('strval', $_checkedFormatsForSiteWeb), true)) {
|
||||
echo '<script>document.getElementById("website-url-fieldset").style.display=""</script>';
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- ═══════════════════ Métadonnées complémentaires ═══════════════════ -->
|
||||
<?php
|
||||
$oldFn = 'old';
|
||||
|
||||
@@ -60,16 +60,6 @@
|
||||
<?php $name = 'language_autre'; $label = 'Autre(s) langue(s) :'; $value = old('language_autre'); include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
||||
</fieldset>
|
||||
|
||||
<!-- ═══════════════════ Format(s) ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Format(s)</legend>
|
||||
<?php
|
||||
$checkedFormats = $formData['formats'] ?? $currentFormats;
|
||||
$name = 'formats'; $label = 'Format(s) du TFE :'; $options = $formatTypes; $checked = $checkedFormats; $required = true;
|
||||
include APP_ROOT . '/templates/partials/form/checkbox-list.php';
|
||||
?>
|
||||
</fieldset>
|
||||
|
||||
<!-- ═══════════════════ Mots-clés ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Mots-clés</legend>
|
||||
@@ -132,6 +122,20 @@
|
||||
require APP_ROOT . '/templates/partials/form/jury-fieldset.php';
|
||||
?>
|
||||
|
||||
<!-- ═══════════════════ Format(s) ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Format(s)</legend>
|
||||
<?php
|
||||
$checkedFormats = $formData['formats'] ?? $currentFormats ?? [];
|
||||
$name = 'formats'; $label = 'Format(s) du TFE :'; $options = $formatTypes; $checked = $checkedFormats; $required = true;
|
||||
$hxPost = '/partage/format-website-fragment';
|
||||
$hxTarget = '#website-url-fieldset';
|
||||
// Capture before include unsets it
|
||||
$_checkedFormatsForSiteWeb = $checked;
|
||||
include APP_ROOT . '/templates/partials/form/checkbox-list.php';
|
||||
?>
|
||||
</fieldset>
|
||||
|
||||
<!-- ═══════════════════ Fichiers ═══════════════════ -->
|
||||
<fieldset>
|
||||
<legend>Fichiers</legend>
|
||||
@@ -173,20 +177,25 @@
|
||||
$fType === 'video' || in_array($fExt, ['mp4','webm','mov','ogv']) => '🎬',
|
||||
$fType === 'audio' || in_array($fExt, ['mp3','ogg','wav','flac','aac','m4a']) => '🔊',
|
||||
$fType === 'caption' || $fExt === 'vtt' => '💬',
|
||||
$fType === 'website' => '🌐',
|
||||
default => '📎',
|
||||
};
|
||||
$isExternalUrl = str_starts_with($f['file_path'] ?? '', 'http://') || str_starts_with($f['file_path'] ?? '', 'https://');
|
||||
$fLinkHref = $isExternalUrl
|
||||
? htmlspecialchars($f['file_path'])
|
||||
: ('/media.php?path=' . urlencode($f['file_path']));
|
||||
?>
|
||||
<li class="admin-file-list-item" data-file-id="<?= (int)$f['id'] ?>">
|
||||
<input type="hidden" name="file_sort_order[]" value="<?= (int)$f['id'] ?>">
|
||||
<span class="admin-file-drag-handle" title="Réordonner">⠿</span>
|
||||
<span class="admin-file-icon-col"><?= $fIcon ?></span>
|
||||
<span class="admin-file-info">
|
||||
<a href="/media.php?path=<?= urlencode($f['file_path']) ?>" target="_blank" rel="noopener" class="admin-file-name">
|
||||
<a href="<?= $fLinkHref ?>" target="_blank" rel="noopener" class="admin-file-name">
|
||||
<?= htmlspecialchars($f['file_name'] ?? basename($f['file_path'])) ?>
|
||||
</a>
|
||||
<span class="admin-file-meta-row">
|
||||
<span class="admin-file-type-badge"><?= htmlspecialchars($fType) ?></span>
|
||||
<?php if (!empty($f['file_size'])): ?>
|
||||
<?php if (!empty($f['file_size']) && $f['file_size'] > 0): ?>
|
||||
<span class="admin-file-size"><?= number_format($f['file_size'] / 1024 / 1024, 2) ?> MB</span>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
@@ -239,6 +248,55 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<!-- Website URL fieldset — shown/hidden via HTMX when "Site web" checked -->
|
||||
<?php
|
||||
// Extract existing website URL/label from thesis_files for initial render
|
||||
$existingWebsite = null;
|
||||
$existingWebsiteLabel = '';
|
||||
foreach ($currentFiles as $f) {
|
||||
if ($f['file_type'] === 'website') {
|
||||
$existingWebsite = $f['file_path'] ?? '';
|
||||
$existingWebsiteLabel = $f['display_label'] ?? '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<fieldset id="website-url-fieldset" style="display:none">
|
||||
<legend>Site web</legend>
|
||||
|
||||
<div class="admin-form-group">
|
||||
<label for="website_url">URL du site :</label>
|
||||
<div class="admin-file-input">
|
||||
<input type="url"
|
||||
id="website_url"
|
||||
name="website_url"
|
||||
value="<?= htmlspecialchars($existingWebsite ?? '') ?>"
|
||||
placeholder="https://mon-tfe.erg.be">
|
||||
<small>Si le TFE est un site web, entrez son URL ici. Il sera affiché comme un site embarqué sur la page du TFE.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-form-group">
|
||||
<label for="website_label">Légende :</label>
|
||||
<input type="text"
|
||||
id="website_label"
|
||||
name="website_label"
|
||||
value="<?= htmlspecialchars($existingWebsiteLabel) ?>"
|
||||
placeholder="Description du site (optionnel)"
|
||||
class="admin-file-label-input"
|
||||
style="max-width:400px;">
|
||||
</div>
|
||||
</fieldset>
|
||||
<?php
|
||||
// Server-side: show if Site web already checked
|
||||
$_stmt = Database::getInstance()->getConnection()->prepare('SELECT id FROM format_types WHERE name = ? LIMIT 1');
|
||||
$_stmt->execute(['Site web']);
|
||||
$_siteWebId = $_stmt->fetchColumn();
|
||||
if ($_siteWebId && in_array((string)$_siteWebId, array_map('strval', $_checkedFormatsForSiteWeb), true)) {
|
||||
echo '<script>document.getElementById("website-url-fieldset").style.display=""</script>';
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- ═══════════════════ Métadonnées complémentaires ═══════════════════ -->
|
||||
<?php
|
||||
$editMetaFormData = [
|
||||
|
||||
@@ -13,14 +13,26 @@
|
||||
* array $options — each element must have 'id' and 'name' keys
|
||||
* array $checked — array of 'id' values that are currently checked
|
||||
* bool $required — whether at least one checkbox must be checked; default false
|
||||
* string $hxPost — optional hx-post URL for HTMX live update
|
||||
* string $hxTarget — optional hx-target CSS selector for HTMX swap
|
||||
*/
|
||||
|
||||
$checked = $checked ?? [];
|
||||
$required = $required ?? false;
|
||||
$checked = $checked ?? [];
|
||||
$required = $required ?? false;
|
||||
$hxPost = $hxPost ?? '';
|
||||
$hxTarget = $hxTarget ?? '';
|
||||
?>
|
||||
<div>
|
||||
<span class="admin-row-label"><?= htmlspecialchars($label) ?><?= $required ? ' <span class="asterisk">*</span>' : '' ?></span>
|
||||
<fieldset class="admin-checkbox-group"<?= $required ? ' required aria-required="true"' : '' ?>>
|
||||
<fieldset class="admin-checkbox-group"
|
||||
<?= $required ? ' required aria-required="true"' : '' ?>
|
||||
<?php if ($hxPost !== ''): ?>
|
||||
hx-post="<?= htmlspecialchars($hxPost) ?>"
|
||||
hx-target="<?= htmlspecialchars($hxTarget) ?>"
|
||||
hx-trigger="change"
|
||||
hx-include="this, #website-url-fieldset"
|
||||
hx-swap="outerHTML"
|
||||
<?php endif; ?>>
|
||||
<legend class="sr-only"><?= htmlspecialchars($label) ?></legend>
|
||||
<ul>
|
||||
<?php foreach ($options as $opt): ?>
|
||||
@@ -38,4 +50,4 @@ $required = $required ?? false;
|
||||
</fieldset>
|
||||
</div>
|
||||
<?php
|
||||
unset($checked);
|
||||
unset($checked, $hxPost, $hxTarget);
|
||||
|
||||
@@ -438,11 +438,12 @@
|
||||
if ($fileType === 'cover') continue;
|
||||
|
||||
// Determine display category
|
||||
$isImage = in_array($ext, ['jpg','jpeg','png','gif','bmp','webp'], true) || $fileType === 'image';
|
||||
$isVideo = in_array($ext, ['mp4','webm','mov','ogv'], true) || $fileType === 'video';
|
||||
$isAudio = in_array($ext, ['mp3','ogg','oga','wav','flac','aac','m4a'], true) || $fileType === 'audio';
|
||||
$isPdf = ($ext === 'pdf') || $fileType === 'main';
|
||||
$isOther = !($isImage || $isVideo || $isAudio || $isPdf);
|
||||
$isImage = in_array($ext, ['jpg','jpeg','png','gif','bmp','webp'], true) || $fileType === 'image';
|
||||
$isVideo = in_array($ext, ['mp4','webm','mov','ogv'], true) || $fileType === 'video';
|
||||
$isAudio = in_array($ext, ['mp3','ogg','oga','wav','flac','aac','m4a'], true) || $fileType === 'audio';
|
||||
$isPdf = ($ext === 'pdf') || $fileType === 'main';
|
||||
$isWebsite = ($fileType === 'website');
|
||||
$isOther = !($isImage || $isVideo || $isAudio || $isPdf || $isWebsite);
|
||||
|
||||
$_vttPath = null;
|
||||
if ($isVideo) {
|
||||
@@ -451,8 +452,10 @@
|
||||
}
|
||||
|
||||
$caption = !empty($file["display_label"]) ? $file["display_label"] : ($file["description"] ?? '');
|
||||
$mediaUrl = '/media?path=' . urlencode($file["file_path"]);
|
||||
$fileName = htmlspecialchars($file["file_name"] ?? basename($file["file_path"]));
|
||||
$filePath = $file['file_path'] ?? '';
|
||||
$isExternalUrl = str_starts_with($filePath, 'http://') || str_starts_with($filePath, 'https://');
|
||||
$mediaUrl = $isExternalUrl ? htmlspecialchars($filePath) : ('/media?path=' . urlencode($filePath));
|
||||
$fileName = htmlspecialchars($file["file_name"] ?? basename($filePath));
|
||||
?>
|
||||
<figure>
|
||||
<?php if ($isPdf): ?>
|
||||
@@ -464,6 +467,20 @@
|
||||
<p class="tfe-pdf-fallback">
|
||||
<a href="<?= $mediaUrl ?>&download=1">Télécharger le PDF</a>
|
||||
</p>
|
||||
<?php elseif ($isWebsite): ?>
|
||||
<iframe src="<?= $mediaUrl ?>"
|
||||
width="100%" height="700px"
|
||||
style="border:none"
|
||||
title="<?= $fileName ?>"
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
loading="lazy">
|
||||
</iframe>
|
||||
<p class="tfe-pdf-fallback">
|
||||
<a href="<?= $mediaUrl ?>" target="_blank" rel="noopener">
|
||||
Ouvrir le site dans un nouvel onglet
|
||||
<span class="sr-only">(ouvre dans un nouvel onglet)</span>
|
||||
</a>
|
||||
</p>
|
||||
<?php elseif ($isImage): ?>
|
||||
<img src="<?= $mediaUrl ?>"
|
||||
alt="<?= htmlspecialchars($caption !== '' ? $caption : $data['title'] . ' — ' . ($data['authors'] ?? '')) ?>">
|
||||
|
||||
Reference in New Issue
Block a user