2025-02-14 18:15:23 +01:00
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
2025-02-15 13:03:10 +01:00
|
|
|
let currentChapterId = null;
|
|
|
|
const storyId = document.querySelector('input[name="id"]')?.value;
|
|
|
|
|
|
|
|
// Initialisation de l'éditeur Quill avec toutes les options
|
2025-02-14 18:15:23 +01:00
|
|
|
const quill = new Quill('#editor', {
|
|
|
|
theme: 'snow',
|
|
|
|
modules: {
|
|
|
|
toolbar: [
|
2025-02-15 13:03:10 +01:00
|
|
|
[{ 'header': [1, 2, 3, false] }],
|
|
|
|
['bold', 'italic', 'underline', 'strike'],
|
|
|
|
[{ 'color': [] }, { 'background': [] }],
|
|
|
|
[{ 'font': [] }],
|
|
|
|
[{ 'align': [] }],
|
|
|
|
['blockquote', 'code-block'],
|
2025-02-14 18:15:23 +01:00
|
|
|
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
2025-02-15 13:03:10 +01:00
|
|
|
[{ 'script': 'sub'}, { 'script': 'super' }],
|
|
|
|
[{ 'indent': '-1'}, { 'indent': '+1' }],
|
|
|
|
[{ 'direction': 'rtl' }],
|
|
|
|
['link', 'image', 'video'],
|
2025-02-14 18:15:23 +01:00
|
|
|
['clean']
|
2025-02-15 13:03:10 +01:00
|
|
|
],
|
|
|
|
keyboard: {
|
|
|
|
bindings: {
|
|
|
|
tab: false,
|
|
|
|
'indent backwards': false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
placeholder: 'Commencez à écrire votre chapitre ici...',
|
|
|
|
formats: [
|
|
|
|
'header',
|
|
|
|
'bold', 'italic', 'underline', 'strike',
|
|
|
|
'color', 'background',
|
|
|
|
'font',
|
|
|
|
'align',
|
|
|
|
'blockquote', 'code-block',
|
|
|
|
'list', 'bullet',
|
|
|
|
'script',
|
|
|
|
'indent',
|
|
|
|
'direction',
|
|
|
|
'link', 'image', 'video'
|
|
|
|
]
|
2025-02-14 18:15:23 +01:00
|
|
|
});
|
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
// Gestion des chapitres
|
2025-02-14 19:57:45 +01:00
|
|
|
const modal = document.getElementById('chapterEditor');
|
|
|
|
const addChapterBtn = document.getElementById('addChapter');
|
2025-02-15 13:03:10 +01:00
|
|
|
const saveChapterBtn = document.getElementById('saveChapter');
|
|
|
|
const cancelEditBtn = document.getElementById('cancelEdit');
|
|
|
|
const chapterTitleInput = document.getElementById('chapterTitle');
|
|
|
|
const chaptersList = document.getElementById('chaptersList');
|
2025-02-14 19:57:45 +01:00
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
// Configuration de Sortable pour la réorganisation des chapitres
|
2025-02-14 18:15:23 +01:00
|
|
|
if (chaptersList) {
|
|
|
|
new Sortable(chaptersList, {
|
|
|
|
animation: 150,
|
2025-02-15 13:03:10 +01:00
|
|
|
handle: '.chapter-number', // Utiliser le numéro comme poignée de drag
|
2025-02-14 19:57:45 +01:00
|
|
|
ghostClass: 'sortable-ghost',
|
2025-02-15 13:03:10 +01:00
|
|
|
onEnd: async function(evt) {
|
2025-02-14 19:57:45 +01:00
|
|
|
const chapters = Array.from(chaptersList.children).map((item, index) => ({
|
|
|
|
id: item.dataset.id,
|
2025-02-15 13:03:10 +01:00
|
|
|
position: index
|
2025-02-14 19:57:45 +01:00
|
|
|
}));
|
|
|
|
|
|
|
|
try {
|
|
|
|
const response = await fetch('api/reorder-chapters.php', {
|
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
},
|
|
|
|
body: JSON.stringify({
|
|
|
|
storyId: storyId,
|
|
|
|
chapters: chapters
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
throw new Error('Erreur lors de la réorganisation');
|
|
|
|
}
|
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
// Mise à jour des numéros de chapitres
|
2025-02-14 19:57:45 +01:00
|
|
|
chapters.forEach((chapter, index) => {
|
|
|
|
const element = document.querySelector(`[data-id="${chapter.id}"] .chapter-number`);
|
|
|
|
if (element) {
|
|
|
|
element.textContent = index + 1;
|
|
|
|
}
|
|
|
|
});
|
2025-02-15 13:03:10 +01:00
|
|
|
|
2025-02-14 19:57:45 +01:00
|
|
|
} catch (error) {
|
|
|
|
console.error('Erreur:', error);
|
2025-02-15 13:03:10 +01:00
|
|
|
showNotification('Erreur lors de la réorganisation des chapitres', 'error');
|
2025-02-14 19:57:45 +01:00
|
|
|
}
|
|
|
|
}
|
2025-02-14 18:15:23 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
// Gestionnaires d'événements pour l'édition des chapitres
|
2025-02-14 18:15:23 +01:00
|
|
|
if (addChapterBtn) {
|
|
|
|
addChapterBtn.addEventListener('click', () => {
|
2025-02-14 19:57:45 +01:00
|
|
|
currentChapterId = null;
|
2025-02-15 13:03:10 +01:00
|
|
|
chapterTitleInput.value = '';
|
|
|
|
quill.setContents([]);
|
2025-02-14 18:15:23 +01:00
|
|
|
modal.style.display = 'block';
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
if (cancelEditBtn) {
|
|
|
|
cancelEditBtn.addEventListener('click', () => {
|
|
|
|
if (hasUnsavedChanges()) {
|
|
|
|
if (!confirm('Des modifications non sauvegardées seront perdues. Voulez-vous vraiment fermer ?')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
modal.style.display = 'none';
|
|
|
|
});
|
|
|
|
}
|
2025-02-14 19:57:45 +01:00
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
// Gestion des clics sur la liste des chapitres
|
|
|
|
if (chaptersList) {
|
|
|
|
chaptersList.addEventListener('click', async (e) => {
|
|
|
|
const target = e.target;
|
|
|
|
|
|
|
|
if (target.matches('.edit-chapter')) {
|
|
|
|
const chapterItem = target.closest('.chapter-item');
|
|
|
|
currentChapterId = chapterItem.dataset.id;
|
2025-02-14 19:57:45 +01:00
|
|
|
|
|
|
|
try {
|
2025-02-15 13:03:10 +01:00
|
|
|
const response = await fetch(`api/get-chapter.php?storyId=${storyId}&chapterId=${currentChapterId}`);
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
throw new Error('Erreur réseau');
|
|
|
|
}
|
|
|
|
|
|
|
|
const chapter = await response.json();
|
|
|
|
|
|
|
|
// Mise à jour du titre
|
|
|
|
chapterTitleInput.value = chapter.title || '';
|
|
|
|
|
|
|
|
// Gestion du contenu
|
|
|
|
if (chapter.html) {
|
|
|
|
// Si on a du HTML, on le charge directement
|
|
|
|
quill.root.innerHTML = chapter.html;
|
|
|
|
} else if (chapter.content) {
|
|
|
|
// Si on a du contenu au format Delta
|
|
|
|
try {
|
|
|
|
const content = typeof chapter.content === 'string'
|
|
|
|
? JSON.parse(chapter.content)
|
|
|
|
: chapter.content;
|
|
|
|
quill.setContents(content);
|
|
|
|
} catch (contentError) {
|
|
|
|
console.error('Erreur de parsing du contenu:', contentError);
|
|
|
|
quill.setText(chapter.content || '');
|
|
|
|
}
|
2025-02-14 19:57:45 +01:00
|
|
|
} else {
|
2025-02-15 13:03:10 +01:00
|
|
|
// Contenu vide par défaut
|
|
|
|
quill.setContents([]);
|
2025-02-14 19:57:45 +01:00
|
|
|
}
|
2025-02-15 13:03:10 +01:00
|
|
|
|
|
|
|
modal.style.display = 'block';
|
2025-02-14 19:57:45 +01:00
|
|
|
} catch (error) {
|
2025-02-15 13:03:10 +01:00
|
|
|
console.error('Erreur détaillée:', error);
|
|
|
|
showNotification('Erreur lors du chargement du chapitre. Veuillez réessayer.', 'error');
|
2025-02-14 19:57:45 +01:00
|
|
|
}
|
|
|
|
}
|
2025-02-15 13:03:10 +01:00
|
|
|
});
|
|
|
|
}
|
2025-02-14 19:57:45 +01:00
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
// Système de notification
|
|
|
|
function showNotification(message, type = 'success') {
|
|
|
|
const notification = document.createElement('div');
|
|
|
|
notification.className = `notification ${type}`;
|
|
|
|
notification.textContent = message;
|
|
|
|
|
|
|
|
document.body.appendChild(notification);
|
|
|
|
|
|
|
|
// Animation d'entrée
|
|
|
|
setTimeout(() => {
|
|
|
|
notification.style.opacity = '1';
|
|
|
|
notification.style.transform = 'translateY(0)';
|
|
|
|
}, 10);
|
|
|
|
|
|
|
|
// Auto-suppression après 3 secondes
|
|
|
|
setTimeout(() => {
|
|
|
|
notification.style.opacity = '0';
|
|
|
|
notification.style.transform = 'translateY(-100%)';
|
|
|
|
setTimeout(() => notification.remove(), 300);
|
|
|
|
}, 3000);
|
|
|
|
}
|
2025-02-14 19:57:45 +01:00
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
// Vérification des changements non sauvegardés
|
|
|
|
function hasUnsavedChanges() {
|
|
|
|
if (!currentChapterId) {
|
|
|
|
return chapterTitleInput.value !== '' || quill.getLength() > 1;
|
|
|
|
}
|
|
|
|
// Pour les chapitres existants, il faudrait comparer avec le contenu original
|
|
|
|
return true; // Par défaut, on suppose qu'il y a des changements
|
|
|
|
}
|
2025-02-14 19:57:45 +01:00
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
// Sauvegarde d'un chapitre
|
|
|
|
if (saveChapterBtn) {
|
|
|
|
saveChapterBtn.addEventListener('click', async () => {
|
|
|
|
const title = chapterTitleInput.value.trim();
|
|
|
|
if (!title) {
|
|
|
|
showNotification('Le titre est requis', 'error');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-02-14 19:57:45 +01:00
|
|
|
try {
|
2025-02-15 13:03:10 +01:00
|
|
|
const response = await fetch('api/save-chapter.php', {
|
2025-02-14 18:15:23 +01:00
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
},
|
|
|
|
body: JSON.stringify({
|
2025-02-14 19:57:45 +01:00
|
|
|
storyId: storyId,
|
2025-02-15 13:03:10 +01:00
|
|
|
chapterId: currentChapterId,
|
|
|
|
title: title,
|
|
|
|
content: JSON.stringify(quill.getContents())
|
2025-02-14 18:15:23 +01:00
|
|
|
})
|
|
|
|
});
|
2025-02-15 13:03:10 +01:00
|
|
|
|
|
|
|
if (response.ok) {
|
|
|
|
showNotification('Chapitre sauvegardé avec succès');
|
|
|
|
setTimeout(() => location.reload(), 500);
|
|
|
|
} else {
|
|
|
|
throw new Error('Erreur lors de la sauvegarde');
|
|
|
|
}
|
2025-02-14 18:15:23 +01:00
|
|
|
} catch (error) {
|
2025-02-14 19:57:45 +01:00
|
|
|
console.error('Erreur:', error);
|
2025-02-15 13:03:10 +01:00
|
|
|
showNotification('Erreur lors de la sauvegarde du chapitre', 'error');
|
2025-02-14 18:15:23 +01:00
|
|
|
}
|
2025-02-15 13:03:10 +01:00
|
|
|
});
|
|
|
|
}
|
2025-02-14 18:15:23 +01:00
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
// Ajouter le style des notifications
|
|
|
|
const style = document.createElement('style');
|
|
|
|
style.textContent = `
|
|
|
|
.notification {
|
|
|
|
position: fixed;
|
|
|
|
top: 20px;
|
|
|
|
right: 20px;
|
|
|
|
padding: 1rem 2rem;
|
|
|
|
border-radius: var(--radius-sm);
|
|
|
|
background: white;
|
|
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
|
opacity: 0;
|
|
|
|
transform: translateY(-100%);
|
|
|
|
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
|
|
z-index: 1000;
|
2025-02-14 19:57:45 +01:00
|
|
|
}
|
2025-02-14 18:15:23 +01:00
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
.notification.success {
|
|
|
|
background-color: var(--success-color);
|
|
|
|
color: white;
|
2025-02-14 18:15:23 +01:00
|
|
|
}
|
|
|
|
|
2025-02-15 13:03:10 +01:00
|
|
|
.notification.error {
|
|
|
|
background-color: var(--error-color);
|
|
|
|
color: white;
|
2025-02-14 18:15:23 +01:00
|
|
|
}
|
2025-02-15 13:03:10 +01:00
|
|
|
`;
|
|
|
|
document.head.appendChild(style);
|
2025-02-14 19:57:45 +01:00
|
|
|
});
|