197 lines
6.9 KiB
JavaScript
197 lines
6.9 KiB
JavaScript
(function () {
|
|
"use strict";
|
|
|
|
function getCookie(name) {
|
|
if (!document.cookie) {
|
|
return null;
|
|
}
|
|
const cookies = document.cookie.split(';');
|
|
for (let i = 0; i < cookies.length; i += 1) {
|
|
const cookie = cookies[i].trim();
|
|
if (cookie.substring(0, name.length + 1) === `${name}=`) {
|
|
return decodeURIComponent(cookie.substring(name.length + 1));
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function escapeHTML(value) {
|
|
if (typeof value !== 'string') {
|
|
return '';
|
|
}
|
|
return value
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
function formatComment(value) {
|
|
const safeValue = escapeHTML(value || '');
|
|
return safeValue.replace(/\n/g, '<br>');
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const modalEl = document.getElementById('operationCommentModal');
|
|
if (!modalEl || typeof bootstrap === 'undefined' || !bootstrap.Modal) {
|
|
return;
|
|
}
|
|
|
|
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
|
|
const form = document.getElementById('operationCommentForm');
|
|
const textarea = document.getElementById('operationCommentTextarea');
|
|
const labelEl = document.getElementById('operationCommentOperationLabel');
|
|
const errorAlert = document.getElementById('operationCommentError');
|
|
const spinner = document.getElementById('operationCommentSpinner');
|
|
const submitBtn = document.getElementById('operationCommentSubmit');
|
|
|
|
let activeOperationId = null;
|
|
let activeEndpoint = null;
|
|
|
|
function setLoadingState(isLoading) {
|
|
if (!submitBtn || !spinner) {
|
|
return;
|
|
}
|
|
submitBtn.disabled = isLoading;
|
|
if (isLoading) {
|
|
spinner.classList.remove('d-none');
|
|
} else {
|
|
spinner.classList.add('d-none');
|
|
}
|
|
}
|
|
|
|
function resetError() {
|
|
if (!errorAlert) {
|
|
return;
|
|
}
|
|
errorAlert.classList.add('d-none');
|
|
errorAlert.textContent = '';
|
|
}
|
|
|
|
function showError(message) {
|
|
if (!errorAlert) {
|
|
return;
|
|
}
|
|
errorAlert.textContent = message || '';
|
|
errorAlert.classList.remove('d-none');
|
|
}
|
|
|
|
function updateDisplays(operationId, commentValue) {
|
|
const trimmed = commentValue || '';
|
|
const html = trimmed ? formatComment(trimmed) : '';
|
|
const displayNodes = document.querySelectorAll(`.operation-comment-text[data-operation-id="${operationId}"]`);
|
|
displayNodes.forEach((node) => {
|
|
const content = node.querySelector('.operation-comment-text-content');
|
|
if (content) {
|
|
content.innerHTML = html;
|
|
}
|
|
if (trimmed) {
|
|
node.classList.remove('d-none');
|
|
} else {
|
|
node.classList.add('d-none');
|
|
}
|
|
});
|
|
|
|
const triggers = document.querySelectorAll(`.operation-comment-trigger[data-operation-id="${operationId}"]`);
|
|
triggers.forEach((trigger) => {
|
|
trigger.dataset.comment = trimmed;
|
|
const addLabel = trigger.dataset.addLabel || '';
|
|
const editLabel = trigger.dataset.editLabel || '';
|
|
const title = trimmed ? (editLabel || addLabel) : (addLabel || editLabel);
|
|
if (title) {
|
|
trigger.setAttribute('title', title);
|
|
trigger.setAttribute('aria-label', title);
|
|
}
|
|
});
|
|
}
|
|
|
|
document.addEventListener('click', (event) => {
|
|
const trigger = event.target.closest('.operation-comment-trigger');
|
|
if (!trigger) {
|
|
return;
|
|
}
|
|
|
|
event.preventDefault();
|
|
activeOperationId = trigger.dataset.operationId || null;
|
|
activeEndpoint = trigger.dataset.endpoint || null;
|
|
|
|
if (!activeOperationId || !activeEndpoint) {
|
|
return;
|
|
}
|
|
|
|
if (labelEl) {
|
|
labelEl.textContent = trigger.dataset.operationLabel || '';
|
|
}
|
|
if (textarea) {
|
|
textarea.value = trigger.dataset.comment || '';
|
|
}
|
|
|
|
resetError();
|
|
setLoadingState(false);
|
|
modal.show();
|
|
});
|
|
|
|
if (modalEl) {
|
|
modalEl.addEventListener('hidden.bs.modal', () => {
|
|
activeOperationId = null;
|
|
activeEndpoint = null;
|
|
if (textarea) {
|
|
textarea.value = '';
|
|
}
|
|
setLoadingState(false);
|
|
resetError();
|
|
});
|
|
}
|
|
|
|
if (!form) {
|
|
return;
|
|
}
|
|
|
|
form.addEventListener('submit', (event) => {
|
|
event.preventDefault();
|
|
if (!activeOperationId || !activeEndpoint) {
|
|
setLoadingState(false);
|
|
return;
|
|
}
|
|
|
|
const commentValue = textarea ? textarea.value.trim() : '';
|
|
setLoadingState(true);
|
|
resetError();
|
|
|
|
fetch(activeEndpoint, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': getCookie('csrftoken') || '',
|
|
'X-Requested-With': 'XMLHttpRequest',
|
|
},
|
|
body: JSON.stringify({ comment: commentValue }),
|
|
credentials: 'same-origin',
|
|
})
|
|
.then((response) => response.json()
|
|
.catch(() => ({}))
|
|
.then((data) => ({ response, data })))
|
|
.then(({ response, data }) => {
|
|
if (!response.ok || !data || !data.success) {
|
|
const fallback = typeof gettext !== 'undefined'
|
|
? gettext("Impossible d'enregistrer le commentaire.")
|
|
: "Impossible d'enregistrer le commentaire.";
|
|
showError((data && data.error) || fallback);
|
|
return;
|
|
}
|
|
updateDisplays(activeOperationId, commentValue);
|
|
modal.hide();
|
|
})
|
|
.catch(() => {
|
|
const fallback = typeof gettext !== 'undefined'
|
|
? gettext('Erreur réseau. Veuillez réessayer.')
|
|
: 'Erreur réseau. Veuillez réessayer.';
|
|
showError(fallback);
|
|
})
|
|
.finally(() => {
|
|
setLoadingState(false);
|
|
});
|
|
});
|
|
});
|
|
}());
|