loko/streetup/interventions/static/interventions/detail/operation_comments.js
2026-07-22 14:48:40 +02:00

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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
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);
});
});
});
}());