From 048a14bc2edc9890ee9a1fb444ae0bd120dc827d Mon Sep 17 00:00:00 2001 From: Pontoporeia Date: Sun, 10 May 2026 10:59:52 +0200 Subject: [PATCH] Add language-search component for Autre Langue input + active search in lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the mots-clé tag-search system: dropdown suggestions from existing languages via HTMX, pill display with bin-icon remove buttons, 'Créer' option for new languages. Replaces the plain text input. - New partial: templates/partials/form/language-search.php - New fragment: public/partage/language-search-fragment.php - Admin wrapper: public/admin/language-search-fragment.php - Updated language-autre-fragment to return just the required asterisk indicator - Updated both controllers to handle language_autre as array (pill-based) with backward-compatible string path - Updated edit form to compute selectedOtherLanguages from DB - Registered new route in partage/index.php - Fix CSV importer: split comma-separated language column into individual entries - Add htmx active search to admin index, title line-clamp, predefined languages only in checkboxes - Admin index: filter form now uses htmx triggers (input delay:300ms on search, change on selects) to actively search without page reload - Sort links include hx-push-url for back-button support - Added loading indicator bar (.admin-search-indicator) - Title column: line-clamp at 2 lines with overflow hidden, native title attr tooltip for full text - Language checkboxes now show only 3 predefined languages (Français, Anglais, Néerlandais); all others go via the Autre langue search component - Added Database::getPredefinedLanguages() and excluded predefined from language-search-fragment suggestions - Included hidden sort/dir inputs in table-wrap so sort state preserved across filter changes - Fix language-search: block 'Créer' for predefined languages in dropdown The 'Créer' option in the language-search dropdown now also checks against the predefined set (français, anglais, néerlandais) to avoid offering creation of languages that already exist as checkboxes. --- TODO.md | 4 + app/public/admin/actions/delete.php | 10 +- app/public/admin/contenus.php | 1 + app/public/admin/index.php | 25 +- app/public/admin/language-search-fragment.php | 13 + app/public/admin/parametres.php | 1 - app/public/assets/css/admin.css | 28 ++ app/public/partage/index.php | 7 + .../partage/language-autre-fragment.php | 22 +- .../partage/language-search-fragment.php | 107 ++++++++ app/src/AdminLogger.php | 6 - .../Controllers/ThesisCreateController.php | 14 +- app/src/Controllers/ThesisEditController.php | 14 +- app/src/Database.php | 26 +- app/templates/admin/acces.php | 13 + app/templates/admin/contenus.php | 126 ++++++++- app/templates/admin/edit.php | 20 ++ app/templates/admin/index-table.php | 18 +- app/templates/admin/index.php | 17 +- app/templates/admin/parametres.php | 142 +--------- app/templates/partials/form/form.php | 48 ++-- .../partials/form/language-search.php | 242 ++++++++++++++++++ 22 files changed, 667 insertions(+), 237 deletions(-) create mode 100644 app/public/admin/language-search-fragment.php create mode 100644 app/public/partage/language-search-fragment.php create mode 100644 app/templates/partials/form/language-search.php diff --git a/TODO.md b/TODO.md index a9e1efc..9392d2a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,9 @@ # TODO +- [x] Remove delete-all TFE from parametres (template, dialog, controller, DB method, logger) +- [x] Move Formulaire + Types de travaux from parametres to contenus under Paramètres du Formulaire h2 +- [x] Restructure contenus Formulaire: sub-headings for Restrictions, Degré d'ouverture, Types de travaux, Structure +- [x] Copy mots-clé htmx system (dropdown, pills, create) to Autre Langue input - [x] Languages: store lowercase, display with ucfirst (getOrCreateLanguage, CSV import, getAllLanguages, v_theses_full, schema seed data, migration 025) - [x] CSV importer: add AP aliases for D&P du multiple, PACS variants, Narraion typo - [x] Move default semantic form element styles (checkbox, radio, select) from admin.css/form.css into common.css diff --git a/app/public/admin/actions/delete.php b/app/public/admin/actions/delete.php index 8f02a2c..e1e53d9 100644 --- a/app/public/admin/actions/delete.php +++ b/app/public/admin/actions/delete.php @@ -16,20 +16,14 @@ if (!isset($_POST['csrf_token'], $_SESSION['csrf_token']) exit; } -$isBulk = !empty($_POST['bulk']); -$isDeleteAll = !empty($_POST['delete_all']); +$isBulk = !empty($_POST['bulk']); try { $db = new Database(); $logger = AdminLogger::make(); - if ($isDeleteAll) { - $count = $db->deleteAllTheses(); - $logger->logDeleteAllTheses($count); - App::flash('success', "$count TFE(s) supprimé(s) avec succès."); - - } elseif ($isBulk) { + if ($isBulk) { $ids = array_filter(array_map('intval', $_POST['selected_theses'] ?? []), fn($id) => $id > 0); if (empty($ids)) { diff --git a/app/public/admin/contenus.php b/app/public/admin/contenus.php index d5b139c..251280a 100644 --- a/app/public/admin/contenus.php +++ b/app/public/admin/contenus.php @@ -18,6 +18,7 @@ try { $pages = array_values(array_filter($allPages, fn($p) => in_array($p['slug'], $allowedPageSlugs, true))); $aproposKeys = $db->getAllAproposContents(); $formHelpBlocks = $db->getAllFormHelpBlocks(); + $siteSettings = $db->getAllSettings(); } catch (Exception $e) { error_log("Error loading contenus: " . $e->getMessage()); die("Erreur lors du chargement des contenus."); diff --git a/app/public/admin/index.php b/app/public/admin/index.php index 54f00d8..f64826e 100644 --- a/app/public/admin/index.php +++ b/app/public/admin/index.php @@ -349,18 +349,21 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { } } if (!empty($languageRaw)) { - $langName = strtolower(trim($languageRaw)); - // Lookup case-insensitively; insert if missing (stored lowercase). - $s = $importPdo->prepare("SELECT id FROM languages WHERE LOWER(name) = LOWER(?)"); - $s->execute([$langName]); - $r = $s->fetch(); - $langId = $r ? (int)$r['id'] : null; - if ($langId === null) { - $importPdo->prepare("INSERT INTO languages (name) VALUES (?)")->execute([$langName]); - $langId = (int)$importPdo->lastInsertId(); + foreach (array_map('trim', explode(',', $languageRaw)) as $langName) { + $langName = strtolower($langName); + if ($langName === '') continue; + // Lookup case-insensitively; insert if missing (stored lowercase). + $s = $importPdo->prepare("SELECT id FROM languages WHERE LOWER(name) = LOWER(?)"); + $s->execute([$langName]); + $r = $s->fetch(); + $langId = $r ? (int)$r['id'] : null; + if ($langId === null) { + $importPdo->prepare("INSERT INTO languages (name) VALUES (?)")->execute([$langName]); + $langId = (int)$importPdo->lastInsertId(); + } + $s2 = $importPdo->prepare("INSERT INTO thesis_languages (thesis_id, language_id) VALUES (?,?)"); + $s2->execute([$thesisId, $langId]); } - $s2 = $importPdo->prepare("INSERT INTO thesis_languages (thesis_id, language_id) VALUES (?,?)"); - $s2->execute([$thesisId, $langId]); } if (!empty($formatsRaw)) { foreach (array_map('trim', explode(',', $formatsRaw)) as $fmt) { diff --git a/app/public/admin/language-search-fragment.php b/app/public/admin/language-search-fragment.php new file mode 100644 index 0000000..91a91fc --- /dev/null +++ b/app/public/admin/language-search-fragment.php @@ -0,0 +1,13 @@ +getAllSettings(); $peerTubeSettings = PeerTubeService::getSettings($db); $peerTubeEnabled = PeerTubeService::isEnabled($db); $peerTubeConfigured = PeerTubeService::isConfigured($db); -$stats = $db->getThesesStats(); $smtpSettings = SmtpRelay::getSettings($db); $smtpConfigured = SmtpRelay::isConfigured($db); $smtpErrorField = $_SESSION['_flash_smtp_field'] ?? null; diff --git a/app/public/assets/css/admin.css b/app/public/assets/css/admin.css index b64c37e..538dce7 100644 --- a/app/public/assets/css/admin.css +++ b/app/public/assets/css/admin.css @@ -379,6 +379,11 @@ th.admin-ap-col { .admin-body table .thesis-title { font-weight: 500; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + word-break: break-word; } .admin-body table .thesis-subtitle { @@ -1943,3 +1948,26 @@ th.admin-ap-col { margin: 0; } } + +/* ── Active search loading indicator ───────────────────────────────────── */ +.admin-search-indicator { + display: block; + height: 2px; + background: var(--accent-primary); + opacity: 0; + transition: opacity 0.15s; + pointer-events: none; + margin-top: var(--space-2xs); +} + +.admin-search-indicator.htmx-request { + opacity: 1; + animation: admin-search-progress 1.2s ease-in-out infinite; +} + +@keyframes admin-search-progress { + 0% { transform: scaleX(0); transform-origin: left; } + 50% { transform: scaleX(1); transform-origin: left; } + 50.01% { transform: scaleX(1); transform-origin: right; } + 100% { transform: scaleX(0); transform-origin: right; } +} diff --git a/app/public/partage/index.php b/app/public/partage/index.php index 3f4d488..b4137a0 100644 --- a/app/public/partage/index.php +++ b/app/public/partage/index.php @@ -56,6 +56,13 @@ if ($slug === 'tag-search-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') { exit; } +// Special route: /partage/language-search-fragment (HTMX fragment — interactive language search) +if ($slug === 'language-search-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') { + App::boot(); + require_once __DIR__ . '/language-search-fragment.php'; + exit; +} + // Special route: /partage/recapitulatif?id=N if ($slug === 'recapitulatif' || $slug === 'recapitulatif.php') { App::boot(); diff --git a/app/public/partage/language-autre-fragment.php b/app/public/partage/language-autre-fragment.php index 1f5fb3b..26f6e84 100644 --- a/app/public/partage/language-autre-fragment.php +++ b/app/public/partage/language-autre-fragment.php @@ -2,9 +2,9 @@ /** * language-autre-fragment.php * - * Shared HTMX fragment include: returns the "Autre(s) langue(s)" input row - * when no standard language checkbox is checked, or the plain (non-required) - * variant when at least one is checked. + * Shared HTMX fragment include: returns the requirement asterisk for the + * "Autre(s) langue(s)" label. When no standard language checkbox is checked, + * an asterisk is rendered to signal the field is required (server-side validated). * * Included by: * - /admin/language-autre-fragment.php (AdminAuth gated) @@ -12,25 +12,11 @@ * * Expected POST: * languages[] — selected language IDs (may be absent) - * language_autre — current free-text value (for repopulation) */ $selectedIds = isset($_POST['languages']) && is_array($_POST['languages']) ? $_POST['languages'] : []; -$currentValue = htmlspecialchars(trim($_POST['language_autre'] ?? '')); $anyChecked = !empty($selectedIds); ?> -
-
- -
- > - Si votre TFE contient une langue absente de la liste, précisez-la ici. -
-
-
+*' : '' ?> diff --git a/app/public/partage/language-search-fragment.php b/app/public/partage/language-search-fragment.php new file mode 100644 index 0000000..3b46b1f --- /dev/null +++ b/app/public/partage/language-search-fragment.php @@ -0,0 +1,107 @@ +getConnection()->prepare( + "SELECT l.id, UPPER(SUBSTR(l.name,1,1)) || SUBSTR(l.name,2) as name, + COUNT(DISTINCT tl.thesis_id) as thesis_count + FROM languages l + LEFT JOIN thesis_languages tl ON l.id = tl.language_id + WHERE LOWER(l.name) LIKE ? + AND LOWER(l.name) NOT IN ($placeholders) + GROUP BY l.id + ORDER BY LOWER(l.name) = ? DESC, thesis_count DESC, LOWER(l.name) + LIMIT 10" + ); + $stmt->execute(array_merge([$query . '%'], $predefined, [$query])); +} else { + $placeholders = implode(',', array_fill(0, count($predefined), '?')); + $stmt = $db->getConnection()->prepare( + "SELECT l.id, UPPER(SUBSTR(l.name,1,1)) || SUBSTR(l.name,2) as name, + COUNT(DISTINCT tl.thesis_id) as thesis_count + FROM languages l + LEFT JOIN thesis_languages tl ON l.id = tl.language_id + WHERE LOWER(l.name) NOT IN ($placeholders) + GROUP BY l.id + ORDER BY thesis_count DESC, LOWER(l.name) + LIMIT 10" + ); + $stmt->execute($predefined); +} + +$results = $stmt->fetchAll(); + +// Deduplicate results by lowercase name +$seen = []; +$results = array_values(array_filter($results, function($lang) use (&$seen) { + $key = strtolower($lang['name']); + if (isset($seen[$key])) return false; + $seen[$key] = true; + return true; +})); + +// Filter out already-selected languages (case-insensitive) +$results = array_values(array_filter($results, function($lang) use ($currentLanguages) { + return !in_array(strtolower($lang['name']), $currentLanguages, true); +})); + +// Check if query exactly matches an existing language (case-insensitive) +// Also check against predefined languages to avoid suggesting creation of a checkbox language +$exactExists = false; +foreach ($results as $lang) { + if (strcasecmp($lang['name'], $query) === 0) { + $exactExists = true; + break; + } +} +if (!$exactExists && $query !== '') { + $normalisedQuery = strtolower($query); + $normalisedPredefined = array_map('strtolower', $predefined); + if (in_array($normalisedQuery, $normalisedPredefined, true)) { + $exactExists = true; + } +} + +// If no exact match and query non-empty, suggest creation +$canCreate = ($query !== '' && !$exactExists && !in_array($query, $currentLanguages, true)); +?> + +
Aucune langue trouvée.
+ + + + + + + + + diff --git a/app/src/AdminLogger.php b/app/src/AdminLogger.php index cfa82ea..7abd489 100644 --- a/app/src/AdminLogger.php +++ b/app/src/AdminLogger.php @@ -194,12 +194,6 @@ class AdminLogger ]); } - /** Parametres: delete all TFEs */ - public function logDeleteAllTheses(int $count): void - { - $this->write('system', 'delete_all_theses', 'success', ['count' => $count]); - } - /** Parametres: formulaire section toggles */ public function logFormSettingsUpdate(array $newValues): void { diff --git a/app/src/Controllers/ThesisCreateController.php b/app/src/Controllers/ThesisCreateController.php index 778b9f7..f68ba9e 100644 --- a/app/src/Controllers/ThesisCreateController.php +++ b/app/src/Controllers/ThesisCreateController.php @@ -114,7 +114,7 @@ class ThesisCreateController 'orientations' => $this->db->getAllOrientations(), 'apPrograms' => $this->db->getAllAPPrograms(), 'finalityTypes' => $this->db->getAllFinalityTypes(), - 'languages' => $this->db->getAllLanguages(), + 'languages' => $this->db->getPredefinedLanguages(), 'formatTypes' => $this->db->getAllFormatTypes(), 'licenseTypes' => $this->db->getAllLicenseTypes(), 'enabledAccessTypes' => $this->db->getEnabledFormAccessTypes(), @@ -467,8 +467,16 @@ class ThesisCreateController $languageIds = isset($post['languages']) && is_array($post['languages']) ? array_map('intval', $post['languages']) : []; - $autreRaw = trim($post['language_autre'] ?? ''); - if ($autreRaw !== '') { + // language_autre: pill-based component sends an array; also handle legacy comma-separated string + $autreRaw = $post['language_autre'] ?? ''; + if (is_array($autreRaw)) { + foreach ($autreRaw as $langName) { + $langName = trim($langName); + if ($langName !== '') { + $languageIds[] = $this->db->getOrCreateLanguage($langName); + } + } + } elseif (is_string($autreRaw) && trim($autreRaw) !== '') { foreach (array_map('trim', explode(',', $autreRaw)) as $langName) { if ($langName !== '') { $languageIds[] = $this->db->getOrCreateLanguage($langName); diff --git a/app/src/Controllers/ThesisEditController.php b/app/src/Controllers/ThesisEditController.php index 58193ec..677d176 100644 --- a/app/src/Controllers/ThesisEditController.php +++ b/app/src/Controllers/ThesisEditController.php @@ -95,7 +95,7 @@ class ThesisEditController $orientations = $this->db->getAllOrientations(); $apPrograms = $this->db->getAllAPPrograms(); $finalityTypes = $this->db->getAllFinalityTypes(); - $languages = $this->db->getAllLanguages(); + $languages = $this->db->getPredefinedLanguages(); $formatTypes = $this->db->getAllFormatTypes(); $licenseTypes = $this->db->getAllLicenseTypes(); $enabledAccessTypes = $this->db->getEnabledFormAccessTypes(); @@ -247,8 +247,16 @@ class ThesisEditController $langIds = isset($post['languages']) && is_array($post['languages']) ? $post['languages'] : []; - $autreRaw = trim($post['language_autre'] ?? ''); - if ($autreRaw !== '') { + // language_autre: pill-based component sends an array; also handle legacy comma-separated string + $autreRaw = $post['language_autre'] ?? ''; + if (is_array($autreRaw)) { + foreach ($autreRaw as $langName) { + $langName = trim($langName); + if ($langName !== '') { + $langIds[] = (string)$this->db->getOrCreateLanguage($langName); + } + } + } elseif (is_string($autreRaw) && trim($autreRaw) !== '') { foreach (array_map('trim', explode(',', $autreRaw)) as $langName) { if ($langName !== '') { $langIds[] = (string)$this->db->getOrCreateLanguage($langName); diff --git a/app/src/Database.php b/app/src/Database.php index a3c6757..12983e9 100644 --- a/app/src/Database.php +++ b/app/src/Database.php @@ -752,6 +752,21 @@ class Database return $stmt->fetchAll(); } + /** + * Return only the predefined / hardcoded languages used as checkboxes + * in the form. All other languages go into the "Autre langue" input. + */ + public function getPredefinedLanguages(): array + { + $stmt = $this->pdo->query( + "SELECT id, UPPER(SUBSTR(name,1,1)) || SUBSTR(name,2) as name, created_at + FROM languages + WHERE LOWER(name) IN ('français', 'anglais', 'néerlandais', 'francais', 'neerlandais') + ORDER BY name" + ); + return $stmt->fetchAll(); + } + // ======================================================================== // ADMIN LIST METHOD // ======================================================================== @@ -1940,17 +1955,6 @@ class Database /** * Delete every thesis in the database. */ - public function deleteAllTheses(): int - { - $ids = $this->pdo->query('SELECT id FROM theses')->fetchAll(\PDO::FETCH_COLUMN); - if (empty($ids)) { - return 0; - } - $count = count($ids); - $this->bulkDeleteTheses($ids); - return $count; - } - /** * Insert a thesis file record. * sort_order defaults to (max existing sort_order + 1) for the thesis. diff --git a/app/templates/admin/acces.php b/app/templates/admin/acces.php index 0ee4e2c..dc9c906 100644 --- a/app/templates/admin/acces.php +++ b/app/templates/admin/acces.php @@ -100,6 +100,19 @@ +%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision) +\\\\\\\ to: sttrwkly ec5606f5 "CSV importer: boolean and ap variants/typos" (rebased revision) ++ $linkName = $link['name'] ?? ''; +++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : ''; +%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: sttrwkly ec5606f5 "CSV importer: boolean and ap variants/typos" (rebased revision) +\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision) +- $linkName = $link['name'] ?? ''; +- $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : ''; +%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: somsyvxz 14a3cd10 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebase destination) +\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: qxuprqpt da941497 "Add language-search component for Autre Langue input + active search in lists" (rebased revision) + $linkName = $link['name'] ?? ''; + $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : ''; + $linkLockedYear = $link['locked_year'] ?? null; ++%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision) ++\\\\\\\ to: qxuprqpt a1b3064d "Add language-search component for Autre Langue input + active search in lists" (rebased revision) +++ $linkName = $link['name'] ?? ''; ++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : ''; ?> diff --git a/app/templates/admin/contenus.php b/app/templates/admin/contenus.php index d830c97..300639d 100644 --- a/app/templates/admin/contenus.php +++ b/app/templates/admin/contenus.php @@ -11,6 +11,116 @@ + +

Paramètres du Formulaire

+ + +
+

Restrictions d'accès aux fichiers

+ +
+ + + + + + +
+
+ + +
+

Degré d'ouverture

+

Options de visibilité disponibles dans le formulaire d'ajout de TFE.

+

L'option Libre ne sera activée qu'à partir de l'année académique prochaine.

+ +
+ + + + + + + + + + +
+
+ + +
+

Types de travaux

+

Active ou désactive les types de travaux dans les formulaires et la consultation. Un type désactivé ne peut plus être soumis ni affiché sur le site.

+

Le type TFE est toujours actif et ne peut pas être désactivé.

+ +
+ + + + + + + + + + +
+
+ +

Pages statiques

@@ -39,14 +149,13 @@
- -

Structure du formulaire étudiant·e

-

- Chaque bloc d'aide s'affiche au-dessus de sa section dans le formulaire de soumission. - Le bouton rond active/désactive l'affichage. -

+ +
+

Structure du Formulaire

+

+ Chaque bloc d'aide s'affiche au-dessus de sa section dans le formulaire de soumission. + Le bouton rond active/désactive l'affichage. +

+
diff --git a/app/templates/admin/edit.php b/app/templates/admin/edit.php index c8d47a9..216d03b 100644 --- a/app/templates/admin/edit.php +++ b/app/templates/admin/edit.php @@ -106,6 +106,26 @@ // Languages — either from flash repopulation or current thesis data $formData['languages'] = $formData['languages'] ?? $currentLanguages ?? []; + // Compute "other" languages (those not in the predefined checkbox list) + $predefinedLangIds = array_column($languages, 'id'); + $otherLangIds = array_diff($currentLanguages ?? [], $predefinedLangIds); + $selectedOtherLanguages = []; + if (!empty($otherLangIds)) { + $allLangs = Database::getInstance()->getAllLanguages(); + $allLangMap = []; + foreach ($allLangs as $al) { + $allLangMap[(int)$al['id']] = $al['name']; + } + foreach ($otherLangIds as $lid) { + $lid = (int)$lid; + if (isset($allLangMap[$lid])) { + $selectedOtherLanguages[] = $allLangMap[$lid]; + } + } + // Sort alphabetically + sort($selectedOtherLanguages, SORT_NATURAL | SORT_FLAG_CASE); + } + // Tags — either from flash repopulation or current thesis data $keywordsStr = $thesis['keywords'] ?? ''; $currentTags = $keywordsStr !== '' ? array_map('trim', explode(',', $keywordsStr)) : []; diff --git a/app/templates/admin/index-table.php b/app/templates/admin/index-table.php index 79f4f71..8ca1a2e 100644 --- a/app/templates/admin/index-table.php +++ b/app/templates/admin/index-table.php @@ -21,6 +21,10 @@ $sortArrow = function(string $col) use ($sortCol, $sortDir): string {
+ + + +
-
+ - - + ✕ Réinitialiser
+ + +
diff --git a/app/templates/admin/parametres.php b/app/templates/admin/parametres.php index 98bb50a..b34cfc6 100644 --- a/app/templates/admin/parametres.php +++ b/app/templates/admin/parametres.php @@ -31,129 +31,6 @@ - - -
- Supprimer tous les TFE -

- Supprime définitivement tous les TFE de la base de données, y compris auteurs, - promoteurs, tags, fichiers associés. Cette action est irréversible. -

-
- - - -
-
- - - -
-

Formulaire

-

Options de visibilité disponibles dans le formulaire d'ajout de TFE.

-

L'option Libre ne sera activée qu'à partir de l'année académique prochaine.

- -
- - - -
- Types d'accès - - - - - - -
- -
- Restriction d'accès aux fichiers - - -
- - -
-
- - -
-

Types de travaux

-

Active ou désactive les types de travaux dans les formulaires et la consultation. Un type désactivé ne peut plus être soumis ni affiché sur le site.

-

Le type TFE est toujours actif et ne peut pas être désactivé.

- -
- - - -
- Types disponibles - - - - - - -
- - -
- -
-

Supprimer tous les TFE

- -
-
-

⚠️ Supprimer définitivement TOUS les TFE ? Cette action est IRRÉVERSIBLE.

-
- -
+ diff --git a/app/templates/partials/form/form.php b/app/templates/partials/form/form.php index aa9553c..cec0b30 100644 --- a/app/templates/partials/form/form.php +++ b/app/templates/partials/form/form.php @@ -186,29 +186,45 @@ $checkedFormatsForSiteWeb = $checkedFormatsForSiteWeb ?? []; $checked = $formData["languages"] ?? []; $required = !$adminMode; $hxPost = $mode === 'partage' ? "/partage/language-autre-fragment" : "/admin/language-autre-fragment.php"; - $hxTarget = "#language-autre-row"; + $hxTarget = "#language-autre-required"; $hxSwap = "outerHTML"; include APP_ROOT . "/templates/partials/form/checkbox-list.php"; unset($hxSwap); ?> trim($_l)]; + } + } + } elseif (!empty($selectedOtherLanguages) && is_array($selectedOtherLanguages)) { + $_selectedOtherLangs = array_map(fn($n) => ['name' => $n], $selectedOtherLanguages); + } else { + $_langRaw = $formData["language_autre"] ?? ''; + if (is_string($_langRaw) && $_langRaw !== '') { + foreach (array_map('trim', explode(',', $_langRaw)) as $_l) { + if ($_l !== '') { + $_selectedOtherLangs[] = ['name' => $_l]; + } + } + } + } + ?> + -
-
- -
- > - Si votre TFE contient une langue absente de la liste, précisez-la ici. -
-
-
- diff --git a/app/templates/partials/form/language-search.php b/app/templates/partials/form/language-search.php new file mode 100644 index 0000000..858bb01 --- /dev/null +++ b/app/templates/partials/form/language-search.php @@ -0,0 +1,242 @@ + int|null, 'name' => string] for pre-filled languages + * string|null $id — override the id attribute prefix + * int $maxLanguages — maximum number of languages (default 10) + * bool $required — whether at least one "other language" is required (default false) + */ + +$name = $name ?? 'language_autre'; +$label = $label ?? 'Autre(s) langue(s)'; +$placeholder = $placeholder ?? 'Rechercher une langue…'; +$hint = $hint ?? null; +$hxPost = $hxPost ?? '/admin/language-search-fragment.php'; +$selectedLanguages = $selectedLanguages ?? []; +$id = $id ?? $name; +$maxLanguages = $maxLanguages ?? 10; +$required = $required ?? false; +$langCount = count($selectedLanguages); +?> +
+ *' : '' ?> +
+ + + + + +
+ + + + + + + +
+ + + + + +
= $maxLanguages ? ' style="display:none"' : '' ?>> + +
+ + +
+
+
+ + + + +