// Admin JavaScript for the backend management interface
// Global object to hold Quill instances
let quillInstances = {};
document.addEventListener('DOMContentLoaded', function() {
// Initialize theme
initTheme();
// Setup dashboard functionality
setupDashboardCards();
// Setup admin forms
setupMatiereForm();
setupSousCategorieForm();
setupTexteForm(); // Basic setup (e.g., category dropdowns if needed)
// Setup content block editor specifically for edit_texte.html
if (document.getElementById('blocks-container')) {
setupContentBlockEditor();
}
// Setup image management (gallery interaction, maybe general upload elsewhere)
setupImageGallery(); // Handles selecting from the modal
// Note: The specific AJAX upload logic is now mainly in edit_texte.html's script block
// but we keep setupImageUploader for potential preview logic or other upload forms.
setupImageUploader(); // Sets up preview for the upload form
// Setup theme toggle
setupThemeToggle();
});
// Initialize theme based on user preference
function initTheme() {
const userPreference = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', userPreference);
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';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
updateThemeIcon(newTheme);
saveThemePreference(newTheme); // Optional: Inform server
});
}
// Update the theme toggle icon based on current theme
function updateThemeIcon(theme) {
const themeToggle = document.getElementById('theme-toggle');
if (!themeToggle) return;
const icon = themeToggle.querySelector('i');
if (!icon) return;
if (theme === 'dark') {
icon.classList.remove('fa-moon');
icon.classList.add('fa-sun');
themeToggle.setAttribute('title', 'Activer le mode clair');
} else {
icon.classList.remove('fa-sun');
icon.classList.add('fa-moon');
themeToggle.setAttribute('title', 'Activer le mode sombre');
}
}
// Save theme preference to server (Optional)
function saveThemePreference(theme) {
// Example using fetch API - adjust URL and method as needed
/*
fetch('/set_theme_preference', { // Replace with your actual endpoint
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Add CSRF token header if needed
// 'X-CSRFToken': getCsrfToken()
},
body: JSON.stringify({ theme: theme })
})
.then(response => response.json())
.then(data => {
if(data.success) console.log('Theme preference saved on server.');
else console.error('Failed to save theme preference on server.');
})
.catch(error => {
console.error('Error saving theme preference:', error);
});
*/
}
// Setup dashboard cards with hover effects
function setupDashboardCards() {
const dashboardCards = document.querySelectorAll('.admin-card');
dashboardCards.forEach(card => {
card.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-5px)';
this.style.boxShadow = 'var(--hover-shadow)';
// Keep transition consistent (defined in CSS is better)
});
card.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0)';
this.style.boxShadow = 'var(--shadow)';
});
});
}
// Setup matiere form functionality (if on matiere page)
function setupMatiereForm() {
const editButtons = document.querySelectorAll('.edit-matiere-btn');
editButtons.forEach(button => {
button.addEventListener('click', function() {
const matiereId = this.getAttribute('data-id');
const matiereName = this.getAttribute('data-name');
const matiereColor = this.getAttribute('data-color');
const editForm = document.getElementById('edit-matiere-form');
const addSection = document.getElementById('add-matiere-section');
const editSection = document.getElementById('edit-matiere-section');
if (editForm && addSection && editSection) {
editForm.querySelector('input[name="matiere_id"]').value = matiereId;
editForm.querySelector('input[name="nom"]').value = matiereName;
const colorInput = editForm.querySelector('input[name="color_code"]');
colorInput.value = matiereColor;
// Trigger input event to update preview if color picker exists
if(colorInput) colorInput.dispatchEvent(new Event('input'));
addSection.classList.add('d-none');
editSection.classList.remove('d-none');
editSection.scrollIntoView({ behavior: 'smooth' });
}
});
});
const cancelEditButton = document.getElementById('cancel-edit-matiere');
if (cancelEditButton) {
cancelEditButton.addEventListener('click', function(e) {
e.preventDefault();
document.getElementById('add-matiere-section')?.classList.remove('d-none');
document.getElementById('edit-matiere-section')?.classList.add('d-none');
});
}
// Color picker preview logic
const colorPickers = document.querySelectorAll('input[type="color"]');
colorPickers.forEach(picker => {
const previewId = picker.id + '-preview'; // Assuming a convention like id="color" and preview span id="color-preview"
let preview = document.getElementById(previewId);
if (!preview) { // Create preview dynamically if not present
preview = document.createElement('span');
preview.className = 'color-preview';
preview.id = previewId;
preview.style.display = 'inline-block';
preview.style.width = '24px';
preview.style.height = '24px';
preview.style.borderRadius = '4px';
preview.style.marginLeft = '10px';
preview.style.verticalAlign = 'middle';
preview.style.border = '1px solid var(--border-color)';
picker.parentNode.insertBefore(preview, picker.nextSibling);
}
picker.addEventListener('input', function() {
preview.style.backgroundColor = this.value;
});
// Initialize preview color
preview.style.backgroundColor = picker.value;
});
}
// Setup sous categorie form functionality (if on sous_categorie page)
function setupSousCategorieForm() {
const editButtons = document.querySelectorAll('.edit-sous-categorie-btn');
editButtons.forEach(button => {
button.addEventListener('click', function() {
const sousCategorieId = this.getAttribute('data-id');
const sousCategorieName = this.getAttribute('data-name');
const matiereId = this.getAttribute('data-matiere-id');
const editForm = document.getElementById('edit-sous-categorie-form');
const addSection = document.getElementById('add-sous-categorie-section');
const editSection = document.getElementById('edit-sous-categorie-section');
if (editForm && addSection && editSection) {
editForm.querySelector('input[name="sous_categorie_id"]').value = sousCategorieId;
editForm.querySelector('input[name="nom"]').value = sousCategorieName;
editForm.querySelector('select[name="matiere_id"]').value = matiereId;
addSection.classList.add('d-none');
editSection.classList.remove('d-none');
editSection.scrollIntoView({ behavior: 'smooth' });
}
});
});
const cancelEditButton = document.getElementById('cancel-edit-sous-categorie');
if (cancelEditButton) {
cancelEditButton.addEventListener('click', function(e) {
e.preventDefault();
document.getElementById('add-sous-categorie-section')?.classList.remove('d-none');
document.getElementById('edit-sous-categorie-section')?.classList.add('d-none');
});
}
// Filter logic if present
const matiereFilterSelect = document.getElementById('matiere-filter');
if (matiereFilterSelect) {
matiereFilterSelect.addEventListener('change', function() {
const selectedMatiereId = this.value;
const tableBody = document.querySelector('.table tbody'); // Adjust selector if needed
if (!tableBody) return;
const sousCategorieRows = tableBody.querySelectorAll('tr'); // Assuming each row represents a sous-categorie
sousCategorieRows.forEach(row => {
// Check if the row has a data attribute identifying the matiere
const rowMatiereId = row.getAttribute('data-matiere-id');
if (rowMatiereId) {
if (selectedMatiereId === '' || rowMatiereId === selectedMatiereId) {
row.style.display = ''; // Show row
} else {
row.style.display = 'none'; // Hide row
}
}
});
});
// Trigger change on load to apply initial filter if a value is pre-selected
matiereFilterSelect.dispatchEvent(new Event('change'));
}
}
// Setup general texte form functionality (e.g., dynamic dropdowns if creating new text)
function setupTexteForm() {
// Example: If there's a matiere dropdown that populates sous-categories on a *creation* page
const matiereSelect = document.getElementById('matiere-select'); // Adjust ID if different
const sousCategorieSelect = document.getElementById('sous-categorie-select'); // Adjust ID
if (matiereSelect && sousCategorieSelect) {
matiereSelect.addEventListener('change', function() {
const matiereId = this.value;
// Clear current sous-categorie options (except the default placeholder)
sousCategorieSelect.innerHTML = '';
sousCategorieSelect.disabled = true;
if (matiereId) {
// Fetch sous-categories for the selected matiere
fetch(`/api/get_sous_categories/${matiereId}`) // Adjust API endpoint
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
if (data && data.length > 0) {
data.forEach(sc => {
const option = document.createElement('option');
option.value = sc.id;
option.textContent = sc.nom;
sousCategorieSelect.appendChild(option);
});
sousCategorieSelect.disabled = false;
} else {
// Handle case with no sous-categories
const option = document.createElement('option');
option.textContent = 'Aucune sous-catégorie trouvée';
option.disabled = true;
sousCategorieSelect.appendChild(option);
}
})
.catch(error => {
console.error('Error loading sous-categories:', error);
// Optionally display an error message to the user
const option = document.createElement('option');
option.textContent = 'Erreur de chargement';
option.disabled = true;
sousCategorieSelect.appendChild(option);
});
}
});
// Trigger change on load if a matiere is pre-selected
if(matiereSelect.value) {
matiereSelect.dispatchEvent(new Event('change'));
}
}
}
// --- Content Block Editor Specific Functions ---
function setupContentBlockEditor() {
const blocksContainer = document.getElementById('blocks-container');
const addBlockButton = document.getElementById('add-block-button');
const saveBlocksButton = document.getElementById('save-blocks-button');
if (!blocksContainer) return; // Only run if the container exists
// Initialize SortableJS for drag-and-drop
if (window.Sortable) {
new Sortable(blocksContainer, {
animation: 150,
handle: '.block-handle', // Class for the drag handle element
ghostClass: 'block-ghost', // Class applied to the ghost element
onEnd: function(evt) {
updateBlockOrder(); // Renumber blocks after drag
}
});
} else {
console.warn('SortableJS not loaded. Drag and drop for blocks disabled.');
}
// Add new block button listener
if (addBlockButton) {
addBlockButton.addEventListener('click', function() {
addContentBlock(); // Add an empty block
});
}
// Save blocks button listener
if (saveBlocksButton) {
saveBlocksButton.addEventListener('click', function() {
saveContentBlocks(); // Gather data and submit the form
});
}
// Setup controls and Quill for existing blocks on page load
setupExistingBlockControls();
}
// Initialize Quill Editor on a given container
function initializeQuillEditor(container, hiddenInput, initialContent = '') {
if (!container || !hiddenInput) {
console.error("Quill initialization failed: Container or hidden input missing.");
return;
}
const blockId = container.id.replace('quill-editor-', '');
// Prevent re-initialization
if (quillInstances[blockId]) {
console.warn(`Quill instance for block ${blockId} already exists.`);
return quillInstances[blockId]; // Return existing instance
}
try {
const quill = new Quill(container, {
theme: 'snow', // Use the 'snow' theme (matches the CSS)
modules: {
toolbar: [
[{ 'header': [1, 2, 3, 4, false] }],
['bold', 'italic', 'underline', 'strike'], // toggled buttons
[{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
[{ 'script': 'sub'}, { 'script': 'super' }], // superscript/subscript
[{ 'indent': '-1'}, { 'indent': '+1' }], // outdent/indent
[{ 'direction': 'rtl' }], // text direction
[{ 'align': [] }],
['link'], // Add link button // Removed 'image' and 'video' as they are handled per block
['blockquote', 'code-block'],
['clean'] // remove formatting button
]
},
placeholder: 'Saisissez le contenu du bloc ici...',
});
// Set initial content if provided. Use dangerouslyPasteHTML for raw HTML.
if (initialContent && initialContent.trim() !== '
') { // Avoid pasting empty paragraph
quill.clipboard.dangerouslyPasteHTML(0, initialContent);
}
// Update hidden input whenever text changes
quill.on('text-change', (delta, oldDelta, source) => {
// Get HTML content from Quill. Handles empty case too.
let htmlContent = quill.root.innerHTML;
// Quill often leaves an empty paragraph tag (
) when cleared. Treat it as empty.
if (htmlContent === '
') {
htmlContent = '';
}
hiddenInput.value = htmlContent;
});
quillInstances[blockId] = quill; // Store the instance
console.log(`Quill initialized for block ${blockId}`);
return quill;
} catch (error) {
console.error(`Error initializing Quill for block ${blockId}:`, error);
container.innerHTML = `
Erreur d'initialisation de l'éditeur pour ce bloc. Contenu brut :
`;
// Still update the hidden input with the original content for safety
hiddenInput.value = initialContent;
return null;
}
}
// Setup controls for existing blocks on page load
function setupExistingBlockControls() {
const blockEditors = document.querySelectorAll('#blocks-container .block-editor');
blockEditors.forEach((blockEditor, index) => {
const blockId = blockEditor.getAttribute('data-block-id');
if (!blockId) {
console.error("Block editor found without data-block-id attribute.", blockEditor);
return; // Skip this block
}
// Initialize Quill for this block
const editorContainer = blockEditor.querySelector(`#quill-editor-${blockId}`);
const hiddenInput = blockEditor.querySelector(`#block-${blockId}-content`);
if (editorContainer && hiddenInput) {
initializeQuillEditor(editorContainer, hiddenInput, hiddenInput.value); // Pass initial content from hidden input
} else {
console.error(`Could not find editor container or hidden input for block ${blockId}`);
}
// Setup Delete Button
const deleteButton = blockEditor.querySelector('.delete-block-btn');
if (deleteButton) {
deleteButton.addEventListener('click', function() {
if (confirm('Êtes-vous sûr de vouloir supprimer ce bloc ? Cette action est irréversible.')) {
// Clean up Quill instance before removing the element
if (quillInstances[blockId]) {
delete quillInstances[blockId]; // Remove reference
console.log(`Quill instance for block ${blockId} cleaned up.`);
}
blockEditor.remove();
updateBlockOrder(); // Renumber remaining blocks
}
});
} else {
console.warn(`Delete button not found for block ${blockId}`);
}
// Setup Image Selection Button
const selectButton = blockEditor.querySelector('.select-image-btn');
if (selectButton) {
selectButton.addEventListener('click', function() {
const galleryModalElement = document.getElementById('image-gallery-modal');
if (galleryModalElement) {
// Store the target block ID on the modal before showing
galleryModalElement.setAttribute('data-target-block', blockId);
// Use Bootstrap's JS to show the modal
const galleryModal = bootstrap.Modal.getOrCreateInstance(galleryModalElement);
galleryModal.show();
} else {
alert("Erreur : La galerie d'images n'a pas pu être trouvée.");
}
});
} else {
console.warn(`Select image button not found for block ${blockId}`);
}
// Setup Image Removal Button
const removeButton = blockEditor.querySelector('.remove-image-btn');
if (removeButton) {
removeButton.addEventListener('click', function() {
const imageIdInput = blockEditor.querySelector('.block-image-id');
const imagePreview = blockEditor.querySelector('.image-preview');
if (imageIdInput) imageIdInput.value = ''; // Clear the hidden ID
if (imagePreview) {
imagePreview.src = '';
imagePreview.style.display = 'none'; // Hide preview
imagePreview.alt = 'Preview';
}
// Toggle button visibility
this.style.display = 'none'; // Hide remove button
const selectBtn = blockEditor.querySelector('.select-image-btn');
if(selectBtn) selectBtn.style.display = 'inline-block'; // Show select button
// Hide position controls (handled by specific function in edit_texte.html)
const event = new CustomEvent('imageRemoved', { bubbles: true, detail: { blockEditor: blockEditor } });
blockEditor.dispatchEvent(event);
});
} else {
console.warn(`Remove image button not found for block ${blockId}`);
}
// Setup Image Position Select (if needed, though primary logic might be in HTML script)
const positionSelect = blockEditor.querySelector('.image-position-select');
if (positionSelect) {
positionSelect.addEventListener('change', function() {
// Optional: Add JS logic here if needed, e.g., apply preview classes
console.log(`Block ${blockId} image position changed to: ${this.value}`);
});
}
});
updateBlockOrder(); // Ensure initial numbering is correct
}
// Add a new content block to the editor
function addContentBlock(data = null) {
const blocksContainer = document.getElementById('blocks-container');
if (!blocksContainer) return;
const blockCount = blocksContainer.children.length;
const newBlockIndex = blockCount + 1;
const blockId = 'new-block-' + Date.now(); // Unique ID for new blocks
// Default values if data is not provided
const initialData = {
id: blockId, // Use the generated temporary ID
title: data?.title || '',
content: data?.content || '', // Default empty content for Quill
image: data?.image || null, // { id: ..., src: ..., alt: ... }
image_position: data?.image_position || 'left'
};
// Create block HTML using template literals
const blockHtml = `
Bloc #${newBlockIndex}
`;
// Add the block HTML to the container
blocksContainer.insertAdjacentHTML('beforeend', blockHtml);
// Get the newly added block element
const newBlockElement = blocksContainer.lastElementChild;
// Initialize Quill for the new block
const editorContainer = newBlockElement.querySelector(`#quill-editor-${initialData.id}`);
const hiddenInput = newBlockElement.querySelector(`#block-${initialData.id}-content`);
if(editorContainer && hiddenInput) {
initializeQuillEditor(editorContainer, hiddenInput, initialData.content);
} else {
console.error(`Failed to find editor elements for new block ${initialData.id}`);
}
// Add event listeners for the new block's controls (delete, select image, remove image)
// Delegate event listeners might be more efficient, but direct binding is simpler here
// Delete button
const deleteButton = newBlockElement.querySelector('.delete-block-btn');
if (deleteButton) {
deleteButton.addEventListener('click', function() {
if (confirm('Êtes-vous sûr de vouloir supprimer ce bloc ?')) {
// Clean up Quill instance
if (quillInstances[initialData.id]) {
delete quillInstances[initialData.id];
console.log(`Quill instance for block ${initialData.id} cleaned up.`);
}
newBlockElement.remove();
updateBlockOrder();
}
});
}
// Select image button
const selectButton = newBlockElement.querySelector('.select-image-btn');
if (selectButton) {
selectButton.addEventListener('click', function() {
const galleryModalElement = document.getElementById('image-gallery-modal');
if (galleryModalElement) {
galleryModalElement.setAttribute('data-target-block', initialData.id);
const galleryModal = bootstrap.Modal.getOrCreateInstance(galleryModalElement);
galleryModal.show();
} else {
alert("Erreur : La galerie d'images n'a pas pu être trouvée.");
}
});
}
// Remove image button
const removeButton = newBlockElement.querySelector('.remove-image-btn');
if (removeButton) {
removeButton.addEventListener('click', function() {
const imageIdInput = newBlockElement.querySelector('.block-image-id');
const imagePreview = newBlockElement.querySelector('.image-preview');
if (imageIdInput) imageIdInput.value = '';
if (imagePreview) {
imagePreview.src = '';
imagePreview.style.display = 'none';
imagePreview.alt = 'Preview';
}
this.style.display = 'none'; // Hide remove button
const selectBtn = newBlockElement.querySelector('.select-image-btn');
if (selectBtn) selectBtn.style.display = 'inline-block'; // Show select button
// Hide position controls
const event = new CustomEvent('imageRemoved', { bubbles: true, detail: { blockEditor: newBlockElement } });
newBlockElement.dispatchEvent(event);
});
}
// Scroll to the new block
newBlockElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
// Update block order numbers in the UI titles
function updateBlockOrder() {
const blocks = document.querySelectorAll('#blocks-container .block-editor');
blocks.forEach((block, index) => {
const titleEl = block.querySelector('.block-editor-title');
if (titleEl) {
titleEl.textContent = `Bloc #${index + 1}`;
}
});
console.log("Block order updated.");
}
// Save content blocks by gathering data and submitting the form
function saveContentBlocks() {
const blocksContainer = document.getElementById('blocks-container');
const blocksDataInput = document.getElementById('blocks-data');
const blocksForm = document.getElementById('blocks-form');
if (!blocksContainer || !blocksDataInput || !blocksForm) {
console.error("Cannot save blocks: Missing container, data input, or form element.");
alert("Erreur : Impossible de sauvegarder les blocs. Éléments de formulaire manquants.");
return;
}
const blockElements = blocksContainer.querySelectorAll('.block-editor');
const blocksData = [];
console.log(`Gathering data for ${blockElements.length} blocks...`);
blockElements.forEach((blockElement, index) => {
const blockId = blockElement.getAttribute('data-block-id');
const titleInput = blockElement.querySelector('.block-title');
const hiddenContentInput = blockElement.querySelector('.block-content-hidden');
const imageIdInput = blockElement.querySelector('.block-image-id');
const imagePositionSelect = blockElement.querySelector('.image-position-select');
let content = '';
// Crucially, get the latest content from Quill instance if available
if (quillInstances[blockId]) {
content = quillInstances[blockId].root.innerHTML;
// Treat empty Quill editor as empty string
if (content === '
') {
content = '';
}
// Ensure hidden input is also synced before submission (belt and suspenders)
if (hiddenContentInput) hiddenContentInput.value = content;
} else if (hiddenContentInput) {
// Fallback to hidden input if Quill instance is missing (error condition)
content = hiddenContentInput.value;
console.warn(`Quill instance missing for block ${blockId}. Using hidden input value.`);
} else {
console.error(`Cannot get content for block ${blockId}: No Quill instance and no hidden input.`);
}
const blockDataItem = {
// Include the original block ID if it's not a new one,
// otherwise, the backend should know how to handle blocks without a numeric ID
id: blockId.startsWith('new-block-') ? null : blockId,
temp_id: blockId.startsWith('new-block-') ? blockId : null, // Send temp ID for new blocks if needed
title: titleInput ? titleInput.value.trim() : '',
content: content,
image_id: imageIdInput ? (imageIdInput.value || null) : null, // Send null if empty
image_position: imagePositionSelect ? imagePositionSelect.value : 'left',
order: index // Set the order based on current position
};
blocksData.push(blockDataItem);
});
// Set the JSON data in the hidden input field
blocksDataInput.value = JSON.stringify(blocksData);
console.log("Blocks data prepared:", blocksDataInput.value);
// Submit the form
// Add loading indicator?
const saveButton = document.getElementById('save-blocks-button');
if(saveButton) {
saveButton.disabled = true;
saveButton.innerHTML = ' Sauvegarde...';
}
blocksForm.submit();
}
// --- Image Management Functions ---
// Setup image uploader preview (for the form in edit_texte.html)
function setupImageUploader() {
const imageFileInput = document.getElementById('image-file'); // ID from edit_texte.html form
const imagePreview = document.getElementById('upload-image-preview'); // ID from edit_texte.html form
if (imageFileInput && imagePreview) {
imageFileInput.addEventListener('change', function() {
if (this.files && this.files[0]) {
const reader = new FileReader();
reader.onload = function(e) {
imagePreview.src = e.target.result;
imagePreview.style.display = 'block'; // Show preview
};
reader.readAsDataURL(this.files[0]);
} else {
// Clear preview if no file selected
imagePreview.src = '#';
imagePreview.style.display = 'none';
}
});
}
}
// Setup image gallery modal interaction
function setupImageGallery() {
const galleryModalElement = document.getElementById('image-gallery-modal');
if (!galleryModalElement) return;
const galleryContent = galleryModalElement.querySelector('#image-gallery-content'); // Container for images
// Use event delegation on the modal body for image clicks
galleryModalElement.addEventListener('click', function(event) {
const galleryItem = event.target.closest('.gallery-item');
if (!galleryItem) return; // Clicked outside an item
const imageId = galleryItem.getAttribute('data-image-id');
const imageElement = galleryItem.querySelector('img');
const imageSrc = imageElement ? imageElement.src : '';
const imageAlt = imageElement ? imageElement.alt : '';
// Get the ID of the block that opened the modal
const targetBlockId = galleryModalElement.getAttribute('data-target-block');
if (!targetBlockId) {
console.error("Target block ID not found on modal.");
return;
}
// Find the target block editor element
const blockEditor = document.querySelector(`.block-editor[data-block-id="${targetBlockId}"]`);
if (blockEditor && imageId && imageSrc) {
// Update the block's image ID input
const imageIdInput = blockEditor.querySelector('.block-image-id');
if (imageIdInput) imageIdInput.value = imageId;
// Update the block's image preview
const imagePreview = blockEditor.querySelector('.image-preview');
if (imagePreview) {
imagePreview.src = imageSrc;
imagePreview.alt = imageAlt || 'Prévisualisation';
imagePreview.style.display = 'block'; // Ensure preview is visible
}
// Toggle visibility of select/remove buttons
const selectButton = blockEditor.querySelector('.select-image-btn');
const removeButton = blockEditor.querySelector('.remove-image-btn');
if (selectButton) selectButton.style.display = 'none';
if (removeButton) removeButton.style.display = 'inline-block';
// Show position controls (handled by specific function in edit_texte.html)
const customEvent = new CustomEvent('imageSelected', { bubbles: true, detail: { blockEditor: blockEditor } });
blockEditor.dispatchEvent(customEvent);
// Close the modal
const galleryModalInstance = bootstrap.Modal.getInstance(galleryModalElement);
if (galleryModalInstance) {
galleryModalInstance.hide();
}
} else {
console.error(`Failed to update block ${targetBlockId}. Block editor or image data missing.`);
}
});
// Optional: Add logic here to dynamically load gallery images via AJAX if needed
// E.g., on modal 'show.bs.modal' event
}