Spaces:
Running
Running
// Main application JavaScript for the frontend | |
// Wait for the DOM to be loaded before executing | |
document.addEventListener('DOMContentLoaded', function() { | |
// Initialize theme | |
initTheme(); | |
// Setup interactive elements | |
setupSubjectSelection(); | |
setupCategorySelection(); | |
setupTextSelection(); | |
setupThemeToggle(); | |
// Setup feedback form submission | |
const feedbackForm = document.getElementById('feedback-form'); | |
if (feedbackForm) { | |
feedbackForm.addEventListener('submit', function(e) { | |
const feedbackMessage = document.getElementById('feedback-message'); | |
if (!feedbackMessage.value.trim()) { | |
e.preventDefault(); | |
alert('Veuillez entrer un message avant d\'envoyer votre feedback.'); | |
} | |
}); | |
} | |
}); | |
// Initialize theme based on user preference | |
function initTheme() { | |
const userPreference = localStorage.getItem('theme') || 'light'; | |
document.documentElement.setAttribute('data-theme', userPreference); | |
// Update theme icon | |
updateThemeIcon(userPreference); | |
} | |
// Setup theme toggle functionality | |
function setupThemeToggle() { | |
const themeToggle = document.getElementById('theme-toggle'); | |
if (!themeToggle) return; | |
themeToggle.addEventListener('click', function() { | |
const currentTheme = document.documentElement.getAttribute('data-theme'); | |
const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; | |
// Update theme attribute | |
document.documentElement.setAttribute('data-theme', newTheme); | |
// Save preference to localStorage | |
localStorage.setItem('theme', newTheme); | |
// Update icon | |
updateThemeIcon(newTheme); | |
// Send theme preference to server | |
saveThemePreference(newTheme); | |
}); | |
} | |
// Update the theme toggle icon based on current theme | |
function updateThemeIcon(theme) { | |
const themeToggle = document.getElementById('theme-toggle'); | |
if (!themeToggle) return; | |
// Update icon based on theme | |
if (theme === 'dark') { | |
themeToggle.innerHTML = '<i class="fas fa-sun"></i>'; | |
themeToggle.setAttribute('title', 'Activer le mode clair'); | |
} else { | |
themeToggle.innerHTML = '<i class="fas fa-moon"></i>'; | |
themeToggle.setAttribute('title', 'Activer le mode sombre'); | |
} | |
} | |
// Save theme preference to server | |
function saveThemePreference(theme) { | |
const formData = new FormData(); | |
formData.append('theme', theme); | |
fetch('/set_theme', { | |
method: 'POST', | |
body: formData | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
console.log('Theme preference saved:', data); | |
}) | |
.catch(error => { | |
console.error('Error saving theme preference:', error); | |
}); | |
} | |
// Setup subject selection functionality | |
function setupSubjectSelection() { | |
const subjectCards = document.querySelectorAll('.subject-card'); | |
const subjectSelect = document.getElementById('matiere-select'); | |
// Handle subject card clicks | |
subjectCards.forEach(card => { | |
card.addEventListener('click', function() { | |
const matiereId = this.getAttribute('data-matiere-id'); | |
// Update select element if it exists | |
if (subjectSelect) { | |
subjectSelect.value = matiereId; | |
// Trigger change event to load subcategories | |
const event = new Event('change'); | |
subjectSelect.dispatchEvent(event); | |
} else { | |
loadSubCategories(matiereId); | |
} | |
// Highlight the selected card | |
subjectCards.forEach(c => c.classList.remove('active')); | |
this.classList.add('active'); | |
// Show the categories section | |
const categoriesSection = document.getElementById('sous-categories-section'); | |
if (categoriesSection) { | |
categoriesSection.classList.remove('d-none'); | |
categoriesSection.scrollIntoView({ behavior: 'smooth' }); | |
} | |
}); | |
}); | |
// Handle subject select change | |
if (subjectSelect) { | |
subjectSelect.addEventListener('change', function() { | |
const matiereId = this.value; | |
if (matiereId) { | |
loadSubCategories(matiereId); | |
// Show the categories section | |
const categoriesSection = document.getElementById('sous-categories-section'); | |
if (categoriesSection) { | |
categoriesSection.classList.remove('d-none'); | |
} | |
} | |
}); | |
} | |
} | |
// Load subcategories for the selected subject | |
function loadSubCategories(matiereId) { | |
fetch(`/get_sous_categories/${matiereId}`) | |
.then(response => response.json()) | |
.then(data => { | |
// Update subcategories list | |
const sousCategoriesList = document.getElementById('sous-categories-list'); | |
if (sousCategoriesList) { | |
sousCategoriesList.innerHTML = ''; | |
data.forEach(category => { | |
const item = document.createElement('li'); | |
item.className = 'selection-item'; | |
item.setAttribute('data-category-id', category.id); | |
item.textContent = category.nom; | |
// Add click event | |
item.addEventListener('click', function() { | |
const categoryId = this.getAttribute('data-category-id'); | |
loadTextes(categoryId); | |
// Highlight the selected category | |
const items = sousCategoriesList.querySelectorAll('.selection-item'); | |
items.forEach(i => i.classList.remove('active')); | |
this.classList.add('active'); | |
// Show the texts section | |
const textesSection = document.getElementById('textes-section'); | |
if (textesSection) { | |
textesSection.classList.remove('d-none'); | |
} | |
}); | |
sousCategoriesList.appendChild(item); | |
}); | |
// Show the subcategories section if it's hidden | |
const sousCategoriesSection = document.getElementById('sous-categories-section'); | |
if (sousCategoriesSection) { | |
sousCategoriesSection.classList.remove('d-none'); | |
} | |
} | |
}) | |
.catch(error => { | |
console.error('Error loading subcategories:', error); | |
}); | |
} | |
// Setup category selection functionality | |
function setupCategorySelection() { | |
const categorySelect = document.getElementById('sous-categorie-select'); | |
if (categorySelect) { | |
categorySelect.addEventListener('change', function() { | |
const categoryId = this.value; | |
if (categoryId) { | |
loadTextes(categoryId); | |
// Show the texts section | |
const textesSection = document.getElementById('textes-section'); | |
if (textesSection) { | |
textesSection.classList.remove('d-none'); | |
} | |
} | |
}); | |
} | |
} | |
// Load texts for the selected category | |
function loadTextes(categoryId) { | |
fetch(`/get_textes/${categoryId}`) | |
.then(response => response.json()) | |
.then(data => { | |
// Update texts list | |
const textesList = document.getElementById('textes-list'); | |
if (textesList) { | |
textesList.innerHTML = ''; | |
data.forEach(texte => { | |
const item = document.createElement('li'); | |
item.className = 'selection-item'; | |
item.setAttribute('data-texte-id', texte.id); | |
item.textContent = texte.titre; | |
// Add click event | |
item.addEventListener('click', function() { | |
const texteId = this.getAttribute('data-texte-id'); | |
displayTexte(texteId); | |
// Highlight the selected text | |
const items = textesList.querySelectorAll('.selection-item'); | |
items.forEach(i => i.classList.remove('active')); | |
this.classList.add('active'); | |
}); | |
textesList.appendChild(item); | |
}); | |
// Show the texts section | |
const textesSection = document.getElementById('textes-section'); | |
if (textesSection) { | |
textesSection.classList.remove('d-none'); | |
} | |
// Hide the content section since no text is selected yet | |
const contentSection = document.getElementById('content-section'); | |
if (contentSection) { | |
contentSection.classList.add('d-none'); | |
} | |
} | |
}) | |
.catch(error => { | |
console.error('Error loading texts:', error); | |
}); | |
} | |
// Setup text selection functionality | |
function setupTextSelection() { | |
const texteSelect = document.getElementById('texte-select'); | |
if (texteSelect) { | |
texteSelect.addEventListener('change', function() { | |
const texteId = this.value; | |
if (texteId) { | |
displayTexte(texteId); | |
} | |
}); | |
} | |
} | |
// Display the selected texte with content blocks | |
function displayTexte(texteId) { | |
fetch(`/get_texte/${texteId}`) | |
.then(response => response.json()) | |
.then(data => { | |
const contentSection = document.getElementById('content-section'); | |
const contentTitle = document.getElementById('content-title'); | |
const contentBlocks = document.getElementById('content-blocks'); | |
if (contentSection && contentTitle && contentBlocks) { | |
// Update content title | |
contentTitle.textContent = data.titre; | |
// Update content theme color based on matiere color | |
if (data.color_code) { | |
// Apply color to title underline | |
contentTitle.style.borderBottomColor = data.color_code; | |
// Apply color to all block titles | |
const style = document.createElement('style'); | |
style.id = 'dynamic-block-styles'; | |
const existingStyle = document.getElementById('dynamic-block-styles'); | |
if (existingStyle) { | |
existingStyle.remove(); | |
} | |
style.textContent = ` | |
.content-block-title { | |
border-bottom-color: ${data.color_code} !important; | |
} | |
.content-block { | |
border-left: 4px solid ${data.color_code} !important; | |
} | |
`; | |
document.head.appendChild(style); | |
} | |
// Clear existing content | |
contentBlocks.innerHTML = ''; | |
// Create content blocks | |
if (data.blocks && data.blocks.length > 0) { | |
data.blocks.forEach(block => { | |
// Create block container | |
const blockDiv = document.createElement('div'); | |
blockDiv.className = 'content-block fade-in'; | |
// Check if block has an image | |
if (block.image) { | |
blockDiv.classList.add('block-with-image'); | |
blockDiv.classList.add(`image-${block.image_position || 'left'}`); | |
// Create image container | |
const imageDiv = document.createElement('div'); | |
imageDiv.className = 'block-image-container'; | |
// Create image element | |
const imageEl = document.createElement('img'); | |
imageEl.className = 'block-image'; | |
imageEl.src = block.image.src; | |
imageEl.alt = block.image.alt || 'Illustration'; | |
imageDiv.appendChild(imageEl); | |
blockDiv.appendChild(imageDiv); | |
// Create content container | |
const contentDiv = document.createElement('div'); | |
contentDiv.className = 'block-content-container'; | |
// Add block title if present | |
if (block.title) { | |
const titleEl = document.createElement('h3'); | |
titleEl.className = 'content-block-title'; | |
titleEl.textContent = block.title; | |
contentDiv.appendChild(titleEl); | |
} | |
// Add block content | |
const contentEl = document.createElement('div'); | |
contentEl.className = 'content-block-content'; | |
contentEl.innerHTML = block.content.replace(/\n/g, '<br>'); | |
contentDiv.appendChild(contentEl); | |
blockDiv.appendChild(contentDiv); | |
} else { | |
// No image - simple block | |
// Add block title if present | |
if (block.title) { | |
const titleEl = document.createElement('h3'); | |
titleEl.className = 'content-block-title'; | |
titleEl.textContent = block.title; | |
blockDiv.appendChild(titleEl); | |
} | |
// Add block content | |
const contentEl = document.createElement('div'); | |
contentEl.className = 'content-block-content'; | |
contentEl.innerHTML = block.content.replace(/\n/g, '<br>'); | |
blockDiv.appendChild(contentEl); | |
} | |
// Add the block to the content area | |
contentBlocks.appendChild(blockDiv); | |
}); | |
} else { | |
// Fallback to regular content if no blocks | |
const blockDiv = document.createElement('div'); | |
blockDiv.className = 'content-block'; | |
blockDiv.innerHTML = data.contenu.replace(/\n/g, '<br>'); | |
contentBlocks.appendChild(blockDiv); | |
} | |
// Show the content section | |
contentSection.classList.remove('d-none'); | |
contentSection.scrollIntoView({ behavior: 'smooth' }); | |
} | |
}) | |
.catch(error => { | |
console.error('Error loading texte:', error); | |
}); | |
} | |