personnalisation des pop-up de confirmation/avertissement
This commit is contained in:
parent
5dc3416009
commit
f9a00576dc
@ -186,5 +186,7 @@ $stories = Stories::getAll();
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||
<script src="../assets/js/dialog.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -68,5 +68,7 @@ $stories = Stories::getAll();
|
||||
</main>
|
||||
|
||||
<script src="../assets/js/admin.js"></script>
|
||||
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||
<script src="../assets/js/dialog.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -155,5 +155,7 @@ $config = Config::load();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||
<script src="../assets/js/dialog.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -138,5 +138,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<button type="submit" class="button">Enregistrer les modifications</button>
|
||||
</form>
|
||||
</main>
|
||||
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||
<script src="../assets/js/dialog.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -253,5 +253,7 @@ function generateSlug($title) {
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="../assets/css/dialog.css">
|
||||
<script src="../assets/js/dialog.js"></script>
|
||||
</body>
|
||||
</html>
|
107
assets/css/dialog.css
Normal file
107
assets/css/dialog.css
Normal file
@ -0,0 +1,107 @@
|
||||
/* dialog.css */
|
||||
.confirm-dialog {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.confirm-dialog.show {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.confirm-dialog-content {
|
||||
background-color: var(--bg-tertiary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--spacing-xl);
|
||||
max-width: 90%;
|
||||
width: 400px;
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
transform: translate(-50%, -60%);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.confirm-dialog.show .confirm-dialog-content {
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.confirm-dialog h3 {
|
||||
margin: 0 0 var(--spacing-md);
|
||||
color: var(--text-primary);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.confirm-dialog p {
|
||||
margin: 0 0 var(--spacing-xl);
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.confirm-dialog-buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.confirm-dialog .button {
|
||||
padding: var(--spacing-sm) var(--spacing-lg);
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.confirm-dialog .button.confirm {
|
||||
background-color: var(--accent-primary);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.confirm-dialog .button.confirm:hover {
|
||||
background-color: var(--accent-secondary);
|
||||
}
|
||||
|
||||
.confirm-dialog .button.danger {
|
||||
background-color: var(--error-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.confirm-dialog .button.danger:hover {
|
||||
background-color: #a33;
|
||||
}
|
||||
|
||||
.confirm-dialog .button.cancel {
|
||||
background-color: var(--bg-secondary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.confirm-dialog .button.cancel:hover {
|
||||
background-color: var(--bg-primary);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.confirm-dialog-content {
|
||||
width: calc(100% - 32px);
|
||||
padding: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.confirm-dialog-buttons {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.confirm-dialog .button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
@ -16,7 +16,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
function confirmDeletion(storyId) {
|
||||
const storyCard = document.querySelector(`[data-id="${storyId}"]`).closest('.story-item');
|
||||
const title = storyCard.querySelector('h2').textContent;
|
||||
return confirm(`Voulez-vous vraiment supprimer le roman "${title}" ? Cette action est irréversible.`);
|
||||
|
||||
confirmDialog.show({
|
||||
title: 'Suppression du roman',
|
||||
message: `Voulez-vous vraiment supprimer le roman "${title}" ? Cette action est irréversible.`,
|
||||
confirmText: 'Supprimer',
|
||||
confirmClass: 'danger',
|
||||
onConfirm: async () => {
|
||||
await deleteStory(storyId);
|
||||
}
|
||||
});
|
||||
return false; // Pour empêcher l'exécution immédiate
|
||||
}
|
||||
|
||||
// Suppression d'un roman via l'API
|
||||
@ -78,9 +88,15 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const logoutForm = document.querySelector('.logout-form');
|
||||
if (logoutForm) {
|
||||
logoutForm.addEventListener('submit', (e) => {
|
||||
if (!confirm('Voulez-vous vraiment vous déconnecter ?')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
e.preventDefault();
|
||||
confirmDialog.show({
|
||||
title: 'Confirmation de déconnexion',
|
||||
message: 'Voulez-vous vraiment vous déconnecter ?',
|
||||
confirmText: 'Se déconnecter',
|
||||
onConfirm: () => {
|
||||
logoutForm.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
145
assets/js/dialog.js
Normal file
145
assets/js/dialog.js
Normal file
@ -0,0 +1,145 @@
|
||||
class ConfirmDialog {
|
||||
constructor() {
|
||||
this.createDialog();
|
||||
}
|
||||
|
||||
createDialog() {
|
||||
// Création du conteneur principal
|
||||
this.dialog = document.createElement('div');
|
||||
this.dialog.className = 'confirm-dialog';
|
||||
this.dialog.style.display = 'none';
|
||||
|
||||
// Création du contenu
|
||||
const content = document.createElement('div');
|
||||
content.className = 'confirm-dialog-content';
|
||||
|
||||
// En-tête avec titre
|
||||
this.title = document.createElement('h3');
|
||||
content.appendChild(this.title);
|
||||
|
||||
// Message
|
||||
this.message = document.createElement('p');
|
||||
content.appendChild(this.message);
|
||||
|
||||
// Conteneur des boutons
|
||||
const buttons = document.createElement('div');
|
||||
buttons.className = 'confirm-dialog-buttons';
|
||||
|
||||
// Bouton Confirmer
|
||||
this.confirmButton = document.createElement('button');
|
||||
this.confirmButton.className = 'button confirm';
|
||||
buttons.appendChild(this.confirmButton);
|
||||
|
||||
// Bouton Annuler
|
||||
this.cancelButton = document.createElement('button');
|
||||
this.cancelButton.className = 'button cancel';
|
||||
this.cancelButton.textContent = 'Annuler';
|
||||
buttons.appendChild(this.cancelButton);
|
||||
|
||||
content.appendChild(buttons);
|
||||
this.dialog.appendChild(content);
|
||||
document.body.appendChild(this.dialog);
|
||||
|
||||
// Fermeture au clic en dehors
|
||||
this.dialog.addEventListener('click', (e) => {
|
||||
if (e.target === this.dialog) {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
|
||||
// Fermeture avec Echap
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && this.dialog.style.display === 'block') {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
show(options) {
|
||||
const defaults = {
|
||||
title: 'Confirmation',
|
||||
message: 'Êtes-vous sûr ?',
|
||||
confirmText: 'Confirmer',
|
||||
confirmClass: 'confirm',
|
||||
cancelText: 'Annuler',
|
||||
onConfirm: () => {},
|
||||
onCancel: () => {}
|
||||
};
|
||||
|
||||
const settings = { ...defaults, ...options };
|
||||
|
||||
this.title.textContent = settings.title;
|
||||
this.message.textContent = settings.message;
|
||||
this.confirmButton.textContent = settings.confirmText;
|
||||
this.confirmButton.className = `button ${settings.confirmClass}`;
|
||||
|
||||
// Réinitialisation des événements
|
||||
const newConfirmBtn = this.confirmButton.cloneNode(true);
|
||||
const newCancelBtn = this.cancelButton.cloneNode(true);
|
||||
this.confirmButton.parentNode.replaceChild(newConfirmBtn, this.confirmButton);
|
||||
this.cancelButton.parentNode.replaceChild(newCancelBtn, this.cancelButton);
|
||||
this.confirmButton = newConfirmBtn;
|
||||
this.cancelButton = newCancelBtn;
|
||||
|
||||
// Nouveaux gestionnaires d'événements
|
||||
this.confirmButton.addEventListener('click', () => {
|
||||
settings.onConfirm();
|
||||
this.hide();
|
||||
});
|
||||
|
||||
this.cancelButton.addEventListener('click', () => {
|
||||
settings.onCancel();
|
||||
this.hide();
|
||||
});
|
||||
|
||||
// Affichage avec animation
|
||||
this.dialog.style.display = 'block';
|
||||
requestAnimationFrame(() => {
|
||||
this.dialog.classList.add('show');
|
||||
});
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.dialog.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
this.dialog.style.display = 'none';
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
// Création d'une instance globale
|
||||
const confirmDialog = new ConfirmDialog();
|
||||
|
||||
// Exemple d'utilisation pour la suppression d'un chapitre
|
||||
document.querySelectorAll('.delete-chapter').forEach(button => {
|
||||
button.addEventListener('click', (e) => {
|
||||
const chapterTitle = e.target.closest('.chapter-item').querySelector('.chapter-title').textContent;
|
||||
|
||||
confirmDialog.show({
|
||||
title: 'Supprimer le chapitre',
|
||||
message: `Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`,
|
||||
confirmText: 'Supprimer',
|
||||
confirmClass: 'danger',
|
||||
onConfirm: () => {
|
||||
// Code de suppression existant
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Exemple d'utilisation pour la suppression d'un roman
|
||||
document.querySelectorAll('.delete-story').forEach(button => {
|
||||
button.addEventListener('click', (e) => {
|
||||
const storyTitle = e.target.closest('.story-item').querySelector('h2').textContent;
|
||||
|
||||
confirmDialog.show({
|
||||
title: 'Supprimer le roman',
|
||||
message: `Voulez-vous vraiment supprimer le roman "${storyTitle}" ? Cette action est irréversible.`,
|
||||
confirmText: 'Supprimer',
|
||||
confirmClass: 'danger',
|
||||
onConfirm: () => {
|
||||
// Code de suppression existant
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
@ -183,11 +183,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
if (cancelEditBtn) {
|
||||
cancelEditBtn.addEventListener('click', () => {
|
||||
if (hasUnsavedChanges()) {
|
||||
if (!confirm('Des modifications non sauvegardées seront perdues. Voulez-vous vraiment fermer ?')) {
|
||||
return;
|
||||
}
|
||||
confirmDialog.show({
|
||||
title: 'Modifications non sauvegardées',
|
||||
message: 'Des modifications non sauvegardées seront perdues. Voulez-vous vraiment fermer ?',
|
||||
confirmText: 'Fermer sans sauvegarder',
|
||||
onConfirm: () => {
|
||||
modal.style.display = 'none';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
modal.style.display = 'none';
|
||||
}
|
||||
modal.style.display = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
@ -241,41 +247,44 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const chapterItem = target.closest('.chapter-item');
|
||||
const chapterId = chapterItem.dataset.id;
|
||||
const chapterTitle = chapterItem.querySelector('.chapter-title').textContent;
|
||||
|
||||
if (confirm(`Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`)) {
|
||||
try {
|
||||
const response = await fetch('api/delete-chapter.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
storyId: storyId,
|
||||
chapterId: chapterId
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Erreur réseau');
|
||||
|
||||
confirmDialog.show({
|
||||
title: 'Suppression du chapitre',
|
||||
message: `Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`,
|
||||
confirmText: 'Supprimer',
|
||||
confirmClass: 'danger',
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
const response = await fetch('api/delete-chapter.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
storyId: storyId,
|
||||
chapterId: chapterId
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Erreur réseau');
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
chapterItem.style.opacity = '0';
|
||||
chapterItem.style.transform = 'translateX(-100%)';
|
||||
setTimeout(() => {
|
||||
chapterItem.remove();
|
||||
showNotification('Chapitre supprimé avec succès');
|
||||
}, 300);
|
||||
} else {
|
||||
throw new Error(result.error || 'Erreur lors de la suppression');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur:', error);
|
||||
showNotification(error.message, 'error');
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
// Animation de suppression
|
||||
chapterItem.style.opacity = '0';
|
||||
chapterItem.style.transform = 'translateX(-100%)';
|
||||
setTimeout(() => {
|
||||
chapterItem.remove();
|
||||
showNotification('Chapitre supprimé avec succès');
|
||||
}, 300);
|
||||
} else {
|
||||
throw new Error(result.error || 'Erreur lors de la suppression');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur:', error);
|
||||
showNotification(error.message, 'error');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user