feat: add full screen mode
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
<div><kbd class="bg-gray-700 px-1 rounded">F1</kbd> : Afficher/Masquer cette aide</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-6">
|
||||
<div class="w-full max-w-none space-y-6">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="text-blue-600 hover:text-blue-800 text-sm font-medium mb-2 inline-block">
|
||||
@@ -34,29 +34,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if not grading_elements %}
|
||||
<div class="bg-yellow-50 border border-yellow-200 rounded-md p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-yellow-800">Aucun élément de notation</h3>
|
||||
<div class="mt-2 text-sm text-yellow-700">
|
||||
<p>Cette évaluation n'a pas encore d'éléments de notation configurés. Vous devez d'abord créer des exercices et leurs éléments de notation.</p>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="text-sm font-medium text-yellow-800 underline hover:text-yellow-900">
|
||||
Configurer l'évaluation →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<form method="POST" action="{{ url_for('grading.save_grades', assessment_id=assessment.id) }}" class="space-y-6" id="grading-form">
|
||||
<!-- Guide de saisie unifié moderne -->
|
||||
<div class="bg-gradient-to-r from-blue-50 to-purple-50 border border-blue-200 rounded-lg p-4">
|
||||
<div class="flex justify-between items-start">
|
||||
@@ -88,7 +65,44 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right flex items-center space-x-3">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% if not grading_elements %}
|
||||
<div class="bg-yellow-50 border border-yellow-200 rounded-md p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-yellow-800">Aucun élément de notation</h3>
|
||||
<div class="mt-2 text-sm text-yellow-700">
|
||||
<p>Cette évaluation n'a pas encore d'éléments de notation configurés. Vous devez d'abord créer des exercices et leurs éléments de notation.</p>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<a href="{{ url_for('assessments.detail', id=assessment.id) }}" class="text-sm font-medium text-yellow-800 underline hover:text-yellow-900">
|
||||
Configurer l'évaluation →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<form method="POST" action="{{ url_for('grading.save_grades', assessment_id=assessment.id) }}" class="space-y-6" id="grading-form">
|
||||
<!-- Tableau de saisie -->
|
||||
<div class="bg-white shadow rounded-lg">
|
||||
<div class="px-4 py-3 border-b border-gray-200 flex justify-between items-center">
|
||||
<h2 class="text-base font-medium text-gray-900">Grille de notation</h2>
|
||||
<div class="flex items-center space-x-3">
|
||||
<button type="button" onclick="toggleFullscreen()" id="fullscreen-btn" class="text-xs bg-purple-100 hover:bg-purple-200 text-purple-800 px-3 py-1 rounded transition-colors flex items-center space-x-1" title="Passer en plein écran">
|
||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"></path>
|
||||
</svg>
|
||||
<span>Plein écran</span>
|
||||
</button>
|
||||
<button type="button" onclick="toggleKeyboardHelp()" class="text-xs bg-blue-100 hover:bg-blue-200 text-blue-800 px-2 py-1 rounded transition-colors">
|
||||
📋 F1
|
||||
</button>
|
||||
@@ -98,49 +112,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filtre des élèves -->
|
||||
<div class="bg-white shadow rounded-lg overflow-hidden mb-4">
|
||||
<div class="px-4 py-3 border-b border-gray-200">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-sm font-medium text-gray-700">Filtrer les élèves</h3>
|
||||
<span id="student-count" class="text-xs text-gray-500">{{ students|length }} élève(s)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="relative">
|
||||
<input type="text"
|
||||
id="student-filter"
|
||||
placeholder="Rechercher un élève par nom ou prénom..."
|
||||
class="w-full px-3 py-2 pl-10 text-sm border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<button type="button"
|
||||
id="clear-filter"
|
||||
class="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600 hidden"
|
||||
onclick="clearStudentFilter()">
|
||||
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tableau de saisie -->
|
||||
<div class="bg-white shadow rounded-lg overflow-hidden">
|
||||
<div class="px-4 py-3 border-b border-gray-200">
|
||||
<h2 class="text-base font-medium text-gray-900">Grille de notation</h2>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200 table-fixed">
|
||||
<!-- En-têtes des exercices -->
|
||||
<thead class="bg-gradient-to-r from-indigo-50 to-purple-50">
|
||||
<div class="grading-table-container">
|
||||
<table class="min-w-full divide-y divide-gray-200 table-fixed grading-table">
|
||||
<!-- En-têtes des exercices -->
|
||||
<thead class="bg-gradient-to-r from-indigo-50 to-purple-50 sticky top-0 z-50 shadow-sm">
|
||||
<tr class="border-b-2 border-indigo-200">
|
||||
<th scope="col" class="px-3 py-1.5 text-left text-xs font-medium text-gray-500 uppercase tracking-wider sticky left-0 bg-gradient-to-r from-indigo-50 to-purple-50 border-r border-indigo-200 w-48">
|
||||
Élève
|
||||
@@ -164,10 +140,32 @@
|
||||
</thead>
|
||||
|
||||
<!-- En-têtes des éléments de notation -->
|
||||
<thead class="bg-gray-50">
|
||||
<thead class="bg-gray-50 sticky z-40 shadow-sm" style="top: 3rem;">
|
||||
<tr>
|
||||
<th scope="col" class="px-3 py-1.5 text-left text-xs font-medium text-gray-500 uppercase tracking-wider sticky left-0 bg-gray-50 border-r border-gray-200 w-48">
|
||||
<!-- Vide pour alignement -->
|
||||
<!-- Filtre des élèves intégré -->
|
||||
<div class="relative w-full">
|
||||
<input type="text"
|
||||
id="student-filter"
|
||||
placeholder="Filtrer les élèves..."
|
||||
class="w-full px-2 py-1 pl-6 text-xs border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 focus:border-blue-500 bg-white">
|
||||
<div class="absolute inset-y-0 left-0 pl-2 flex items-center pointer-events-none">
|
||||
<svg class="h-3 w-3 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<button type="button"
|
||||
id="clear-filter"
|
||||
class="absolute inset-y-0 right-0 pr-2 flex items-center text-gray-400 hover:text-gray-600 hidden"
|
||||
onclick="clearStudentFilter()">
|
||||
<svg class="h-3 w-3" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-center mt-1">
|
||||
<span id="student-count" class="text-xs text-gray-500">{{ students|length }} élève(s)</span>
|
||||
</div>
|
||||
</th>
|
||||
{% set current_exercise = '' %}
|
||||
{% for element in grading_elements %}
|
||||
@@ -309,6 +307,61 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- CSS custom pour forcer le sticky et pleine largeur -->
|
||||
<style>
|
||||
/* Pleine largeur pour cette page */
|
||||
|
||||
/* Mode plein écran */
|
||||
.fullscreen-mode {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.fullscreen-overlay {
|
||||
position: fixed !important;
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
width: 100vw !important;
|
||||
height: 100vh !important;
|
||||
z-index: 9999 !important;
|
||||
background: white !important;
|
||||
padding: 1rem !important;
|
||||
overflow: hidden !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.fullscreen-overlay .grading-table-container {
|
||||
flex: 1 !important;
|
||||
min-height: 0 !important;
|
||||
overflow-x: auto !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.grading-table-container {
|
||||
overflow-x: auto;
|
||||
max-height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.grading-table thead {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
background: white;
|
||||
}
|
||||
.grading-table thead:nth-child(2) {
|
||||
top: 3rem;
|
||||
z-index: 40;
|
||||
background: white;
|
||||
}
|
||||
.grading-table th[scope="col"]:first-child {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 51;
|
||||
background: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Légende -->
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -409,7 +462,11 @@ function setupKeyboardNavigation() {
|
||||
// Ctrl+S : Sauvegarder
|
||||
if (e.ctrlKey && e.key === 's') {
|
||||
e.preventDefault();
|
||||
saveForm();
|
||||
if (isFullscreen) {
|
||||
saveFormFromFullscreen();
|
||||
} else {
|
||||
saveForm();
|
||||
}
|
||||
}
|
||||
|
||||
// Ctrl+Z : Annuler dernière modification
|
||||
@@ -785,6 +842,75 @@ function saveForm() {
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Sauvegarder depuis le mode plein écran
|
||||
function saveFormFromFullscreen() {
|
||||
const form = document.getElementById('grading-form');
|
||||
const saveButtonFs = document.getElementById('save-button-fs');
|
||||
const saveTextFs = document.getElementById('save-text-fs');
|
||||
const saveSpinnerFs = document.getElementById('save-spinner-fs');
|
||||
|
||||
if (!form) {
|
||||
console.error('Formulaire non trouvé');
|
||||
showToast('Erreur : formulaire non trouvé', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Animation de sauvegarde en mode plein écran
|
||||
if (saveButtonFs) {
|
||||
saveButtonFs.disabled = true;
|
||||
if (saveTextFs) saveTextFs.textContent = 'Sauvegarde...';
|
||||
if (saveSpinnerFs) saveSpinnerFs.classList.remove('hidden');
|
||||
}
|
||||
|
||||
// Synchroniser les données du mode plein écran vers le formulaire original
|
||||
syncDataFromFullscreenToOriginal();
|
||||
|
||||
// Soumettre le formulaire original
|
||||
setTimeout(() => {
|
||||
form.submit();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Synchroniser les données entre le mode plein écran et le formulaire original
|
||||
function syncDataFromFullscreenToOriginal() {
|
||||
if (!isFullscreen || !fullscreenOverlay) return;
|
||||
|
||||
// Synchroniser tous les champs de saisie
|
||||
const fsInputs = fullscreenOverlay.querySelectorAll('.grading-input, .comment-input');
|
||||
|
||||
fsInputs.forEach(fsInput => {
|
||||
const name = fsInput.name;
|
||||
if (name) {
|
||||
const originalInput = document.querySelector(`[name="${name}"]`);
|
||||
if (originalInput) {
|
||||
originalInput.value = fsInput.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Données synchronisées du plein écran vers le formulaire original');
|
||||
}
|
||||
|
||||
// Synchroniser les données du formulaire original vers le mode plein écran
|
||||
function syncDataFromOriginalToFullscreen() {
|
||||
if (!isFullscreen || !fullscreenOverlay) return;
|
||||
|
||||
// Synchroniser tous les champs de saisie
|
||||
const originalInputs = document.querySelectorAll('#grading-form .grading-input, #grading-form .comment-input');
|
||||
|
||||
originalInputs.forEach(originalInput => {
|
||||
const name = originalInput.name;
|
||||
if (name) {
|
||||
const fsInput = fullscreenOverlay.querySelector(`[name="${name}"]`);
|
||||
if (fsInput) {
|
||||
fsInput.value = originalInput.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Données synchronisées du formulaire original vers le plein écran');
|
||||
}
|
||||
|
||||
// Afficher/Masquer l'aide clavier
|
||||
function toggleKeyboardHelp() {
|
||||
const help = document.getElementById('keyboard-help');
|
||||
@@ -1031,6 +1157,192 @@ function clearStudentFilter() {
|
||||
}
|
||||
}
|
||||
|
||||
// Gestion du mode plein écran
|
||||
let isFullscreen = false;
|
||||
let fullscreenOverlay = null;
|
||||
|
||||
function toggleFullscreen() {
|
||||
const btn = document.getElementById('fullscreen-btn');
|
||||
const btnText = btn.querySelector('span');
|
||||
const btnIcon = btn.querySelector('svg path');
|
||||
const tableContainer = document.querySelector('.bg-white.shadow.rounded-lg');
|
||||
|
||||
if (!isFullscreen) {
|
||||
// Créer l'overlay plein écran
|
||||
fullscreenOverlay = document.createElement('div');
|
||||
fullscreenOverlay.className = 'fullscreen-overlay';
|
||||
|
||||
// Créer la structure plein écran optimisée
|
||||
fullscreenOverlay.innerHTML = `
|
||||
<div class="h-full flex flex-col justify-between">
|
||||
<!-- Header avec contrôles -->
|
||||
<div class="bg-white shadow rounded-t-lg border-b border-gray-200">
|
||||
<div class="px-4 py-3 flex justify-between items-center">
|
||||
<h2 class="text-base font-medium text-gray-900">Grille de notation</h2>
|
||||
<div class="flex items-center space-x-3">
|
||||
<button type="button" onclick="toggleFullscreen()" class="text-xs bg-red-100 hover:bg-red-200 text-red-800 px-3 py-1 rounded transition-colors flex items-center space-x-1" title="Quitter le plein écran">
|
||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 3v3a2 2 0 01-2 2H3m18 0h-3a2 2 0 01-2-2V3m0 18v-3a2 2 0 012-2h3M3 16h3a2 2 0 012 2v3"></path>
|
||||
</svg>
|
||||
<span>Quitter</span>
|
||||
</button>
|
||||
<button type="button" onclick="toggleKeyboardHelp()" class="text-xs bg-blue-100 hover:bg-blue-200 text-blue-800 px-2 py-1 rounded transition-colors">
|
||||
📋 F1
|
||||
</button>
|
||||
<div class="text-xs">
|
||||
<div class="text-blue-700">Progression :</div>
|
||||
<div id="progress-indicator-fs" class="font-semibold text-blue-900">0 / {{ (students|length * grading_elements|length) }} champs</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tableau central extensible -->
|
||||
<div class="flex-1 bg-white shadow-none grading-table-container" style="min-height: 0;">
|
||||
<!-- Le contenu du tableau sera cloné ici -->
|
||||
</div>
|
||||
|
||||
<!-- Footer de sauvegarde fixe en bas -->
|
||||
<div class="bg-white shadow rounded-b-lg border-t border-gray-200">
|
||||
<div class="px-6 py-4 bg-gray-50 flex justify-between items-center">
|
||||
<div class="flex items-center space-x-4 text-sm text-gray-600">
|
||||
<div id="save-status-fs" class="flex items-center">
|
||||
<span class="w-2 h-2 bg-gray-400 rounded-full mr-2"></span>
|
||||
<span>Non sauvegardé</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-3">
|
||||
<button type="button" onclick="resetForm()" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
|
||||
Réinitialiser
|
||||
</button>
|
||||
<button type="button" onclick="saveFormFromFullscreen()" id="save-button-fs" class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700 transition-colors flex items-center">
|
||||
<span id="save-text-fs">Sauvegarder les notes</span>
|
||||
<span id="save-spinner-fs" class="ml-2 w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin hidden"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Cloner seulement le contenu du tableau (table)
|
||||
const originalTable = tableContainer.querySelector('table');
|
||||
const tableClone = originalTable.cloneNode(true);
|
||||
const fsTableContainer = fullscreenOverlay.querySelector('.grading-table-container');
|
||||
fsTableContainer.appendChild(tableClone);
|
||||
|
||||
// Synchroniser les valeurs actuelles du formulaire vers le clone
|
||||
syncDataFromOriginalToFullscreen();
|
||||
|
||||
// Ajouter l'overlay au body
|
||||
document.body.appendChild(fullscreenOverlay);
|
||||
document.body.classList.add('fullscreen-mode');
|
||||
|
||||
// Masquer le conteneur original
|
||||
tableContainer.style.display = 'none';
|
||||
|
||||
// Mettre à jour le bouton
|
||||
btnText.textContent = 'Quitter';
|
||||
btnIcon.setAttribute('d', 'M8 3v3a2 2 0 01-2 2H3m18 0h-3a2 2 0 01-2-2V3m0 18v-3a2 2 0 012-2h3M3 16h3a2 2 0 012 2v3');
|
||||
btn.title = 'Quitter le plein écran';
|
||||
btn.classList.remove('bg-purple-100', 'hover:bg-purple-200', 'text-purple-800');
|
||||
btn.classList.add('bg-red-100', 'hover:bg-red-200', 'text-red-800');
|
||||
|
||||
// Réinitialiser les événements JavaScript sur la copie
|
||||
setupFullscreenEvents();
|
||||
|
||||
isFullscreen = true;
|
||||
} else {
|
||||
// Supprimer l'overlay
|
||||
if (fullscreenOverlay) {
|
||||
document.body.removeChild(fullscreenOverlay);
|
||||
fullscreenOverlay = null;
|
||||
}
|
||||
document.body.classList.remove('fullscreen-mode');
|
||||
|
||||
// Réafficher le conteneur original
|
||||
const tableContainer = document.querySelector('.bg-white.shadow.rounded-lg');
|
||||
tableContainer.style.display = '';
|
||||
|
||||
// Mettre à jour le bouton
|
||||
btnText.textContent = 'Plein écran';
|
||||
btnIcon.setAttribute('d', 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4');
|
||||
btn.title = 'Passer en plein écran';
|
||||
btn.classList.remove('bg-red-100', 'hover:bg-red-200', 'text-red-800');
|
||||
btn.classList.add('bg-purple-100', 'hover:bg-purple-200', 'text-purple-800');
|
||||
|
||||
isFullscreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
function setupFullscreenEvents() {
|
||||
if (!fullscreenOverlay) return;
|
||||
|
||||
// Réattacher les événements nécessaires
|
||||
const filterInput = fullscreenOverlay.querySelector('#student-filter');
|
||||
if (filterInput) {
|
||||
setupStudentFilterForOverlay(filterInput);
|
||||
}
|
||||
|
||||
// Synchroniser l'indicateur de progression
|
||||
const originalIndicator = document.getElementById('progress-indicator');
|
||||
const fsIndicator = fullscreenOverlay.querySelector('#progress-indicator-fs');
|
||||
if (originalIndicator && fsIndicator) {
|
||||
fsIndicator.textContent = originalIndicator.textContent;
|
||||
fsIndicator.className = originalIndicator.className;
|
||||
}
|
||||
|
||||
// Réattacher les événements sur les champs de saisie en mode plein écran
|
||||
const fsInputs = fullscreenOverlay.querySelectorAll('.grading-input, .comment-input');
|
||||
fsInputs.forEach(input => {
|
||||
if (input.classList.contains('grading-input')) {
|
||||
// Événements pour les champs de notation
|
||||
input.addEventListener('input', function() { handleGradeChange(this); });
|
||||
input.addEventListener('change', function() { handleGradeChange(this); });
|
||||
input.addEventListener('focus', function() { handleGradeFocus(this); });
|
||||
input.addEventListener('keydown', function(e) { handleGradeKeydown(e, this); });
|
||||
} else if (input.classList.contains('comment-input')) {
|
||||
// Événements pour les commentaires
|
||||
input.addEventListener('keydown', function(e) { handleCommentKeydown(e, this); });
|
||||
}
|
||||
});
|
||||
|
||||
// Appliquer les couleurs initiales aux champs pré-remplis
|
||||
applyInitialColors();
|
||||
}
|
||||
|
||||
function setupStudentFilterForOverlay(filterInput) {
|
||||
// Réimplémentation simplifiée du filtre pour l'overlay
|
||||
filterInput.addEventListener('input', function() {
|
||||
const searchTerm = this.value.toLowerCase().trim();
|
||||
const rows = fullscreenOverlay.querySelectorAll('.student-row');
|
||||
let visibleCount = 0;
|
||||
|
||||
rows.forEach(row => {
|
||||
const studentName = row.dataset.studentName;
|
||||
const isVisible = !searchTerm || studentName.includes(searchTerm);
|
||||
row.style.display = isVisible ? '' : 'none';
|
||||
if (isVisible) visibleCount++;
|
||||
});
|
||||
|
||||
const studentCount = fullscreenOverlay.querySelector('#student-count');
|
||||
if (studentCount) {
|
||||
studentCount.textContent = `${visibleCount} / ${rows.length} élève(s)`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Raccourci clavier pour le plein écran (F11 ou Échap pour quitter)
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'F11') {
|
||||
e.preventDefault();
|
||||
toggleFullscreen();
|
||||
} else if (e.key === 'Escape' && isFullscreen) {
|
||||
e.preventDefault();
|
||||
toggleFullscreen();
|
||||
}
|
||||
});
|
||||
|
||||
// Gestion de la fermeture de la page avec modifications non sauvegardées
|
||||
window.addEventListener('beforeunload', function(e) {
|
||||
if (unsavedChanges.size > 0) {
|
||||
@@ -1039,4 +1351,4 @@ window.addEventListener('beforeunload', function(e) {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user