fix(teams): escape quotes and apostrophes in JavaScript translation tags

This commit is contained in:
kdeterme 2026-09-02 11:10:23 +02:00
parent faafa8ec23
commit 7c8360bfc1

View file

@ -1131,7 +1131,7 @@ function confirmMoveMember() {
const selected = document.getElementById('moveToTeamId').value; const selected = document.getElementById('moveToTeamId').value;
if (!newName) { if (!newName) {
showError('moveMemberError', "{% trans 'Le nom du membre est requis.' %}"); showError('moveMemberError', "{% trans 'Le nom du membre est requis.'|escapejs %}");
return; return;
} }
@ -1154,8 +1154,8 @@ function confirmMoveMember() {
function openAddMemberModal(teamId, teamName, teamCompanyId) { function openAddMemberModal(teamId, teamName, teamCompanyId) {
document.getElementById('addMemberTeamId').value = teamId !== null ? teamId : ''; document.getElementById('addMemberTeamId').value = teamId !== null ? teamId : '';
const title = teamId !== null const title = teamId !== null
? `{% trans "Ajouter un membre" %} — ${teamName}` ? `{% trans "Ajouter un membre"|escapejs %} — ${teamName}`
: `{% trans "Ajouter un membre non assigné" %}`; : `{% trans "Ajouter un membre non assigné"|escapejs %}`;
document.getElementById('addMemberModalTitle').textContent = title; document.getElementById('addMemberModalTitle').textContent = title;
document.getElementById('newMemberName').value = ''; document.getElementById('newMemberName').value = '';
document.getElementById('newMemberUser').value = ''; document.getElementById('newMemberUser').value = '';
@ -1203,7 +1203,7 @@ function createMember() {
const teamId = document.getElementById('addMemberTeamId').value; const teamId = document.getElementById('addMemberTeamId').value;
document.getElementById('addMemberError').classList.add('d-none'); document.getElementById('addMemberError').classList.add('d-none');
if (!name) { showError('addMemberError', "{% trans 'Le nom du membre est requis.' %}"); return; } if (!name) { showError('addMemberError', "{% trans 'Le nom du membre est requis.'|escapejs %}"); return; }
if (!userId) { showError('addMemberError', '{% trans "L\'utilisateur est requis."|escapejs %}'); return; } if (!userId) { showError('addMemberError', '{% trans "L\'utilisateur est requis."|escapejs %}'); return; }
postJSON( postJSON(
@ -1218,7 +1218,7 @@ function createMember() {
} }
function deleteMember(memberId, memberName) { function deleteMember(memberId, memberName) {
if (!confirm(`{% trans "Supprimer le membre" %} « ${memberName} » ? {% trans "Cette action est irréversible." %}`)) return; if (!confirm(`{% trans "Supprimer le membre"|escapejs %} « ${memberName} » ? {% trans "Cette action est irréversible."|escapejs %}`)) return;
postJSON( postJSON(
`/contracts/teams/members/${memberId}/delete/`, `/contracts/teams/members/${memberId}/delete/`,
@ -1382,7 +1382,7 @@ function renderPlanningMatrix(data) {
// 1. Rendu des en-têtes // 1. Rendu des en-têtes
const theadRow = document.getElementById('planning-table-header-row'); const theadRow = document.getElementById('planning-table-header-row');
theadRow.innerHTML = `<th class="sticky-team-col">{% trans "Équipes" %}</th>`; theadRow.innerHTML = `<th class="sticky-team-col">{% trans "Équipes"|escapejs %}</th>`;
days.forEach(day => { days.forEach(day => {
const th = document.createElement('th'); const th = document.createElement('th');
@ -1396,15 +1396,15 @@ function renderPlanningMatrix(data) {
<div class="flex-grow-1 text-center"> <div class="flex-grow-1 text-center">
<div class="small text-uppercase text-muted" style="font-size:0.75rem;">${escapeHtml(day.day_short)}</div> <div class="small text-uppercase text-muted" style="font-size:0.75rem;">${escapeHtml(day.day_short)}</div>
<div class="fw-bold fs-6">${escapeHtml(day.day_num)}</div> <div class="fw-bold fs-6">${escapeHtml(day.day_num)}</div>
${day.is_today ? '<span class="badge bg-primary text-white mt-1" style="font-size:0.65rem;">{% trans "Aujourd\'hui" %}</span>' : ''} ${day.is_today ? `<span class="badge bg-primary text-white mt-1" style="font-size:0.65rem;">{% trans "Aujourd'hui"|escapejs %}</span>` : ''}
</div> </div>
${CAN_EDIT_TEAMS ? ` ${CAN_EDIT_TEAMS ? `
<div class="dropdown"> <div class="dropdown">
<button class="btn btn-sm btn-link text-muted p-0 dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" title="{% trans 'Options de la journée' %}"></button> <button class="btn btn-sm btn-link text-muted p-0 dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" title="{% trans 'Options de la journée'|escapejs %}"></button>
<ul class="dropdown-menu dropdown-menu-end shadow-sm"> <ul class="dropdown-menu dropdown-menu-end shadow-sm">
<li> <li>
<a class="dropdown-item small" href="javascript:void(0)" onclick="openDuplicateModalForDay('${day.date}')"> <a class="dropdown-item small" href="javascript:void(0)" onclick="openDuplicateModalForDay('${day.date}')">
<i class="bi bi-copy me-2 text-primary"></i>{% trans "Dupliquer cette journée…" %} <i class="bi bi-copy me-2 text-primary"></i>{% trans "Dupliquer cette journée…"|escapejs %}
</a> </a>
</li> </li>
</ul> </ul>
@ -1419,7 +1419,7 @@ function renderPlanningMatrix(data) {
tbody.innerHTML = ''; tbody.innerHTML = '';
if (teams.length === 0) { if (teams.length === 0) {
tbody.innerHTML = `<tr><td colspan="${days.length + 1}" class="text-center text-muted py-4">{% trans "Aucune équipe trouvée." %}</td></tr>`; tbody.innerHTML = `<tr><td colspan="${days.length + 1}" class="text-center text-muted py-4">{% trans "Aucune équipe trouvée."|escapejs %}</td></tr>`;
return; return;
} }
@ -1469,14 +1469,15 @@ function createPlanningMemberCard(member, teamId, dateStr, canEdit) {
card.dataset.date = dateStr; card.dataset.date = dateStr;
card.dataset.memberName = member.name; card.dataset.memberName = member.name;
const initials = member.name ? member.name.substring(0, 2).toUpperCase() : '??';
let absenceBadge = ''; let absenceBadge = '';
if (member.is_absent) { if (member.is_absent) {
const reasonDisplay = (member.absence && member.absence.reason_display) ? member.absence.reason_display : "{% trans 'Absent' %}"; const reasonDisplay = (member.absence && member.absence.reason_display) ? member.absence.reason_display : "{% trans 'Absent'|escapejs %}";
absenceBadge = `<span class="badge bg-danger text-white me-1" style="font-size:0.65rem;" title="${escapeHtml(member.absence?.comment || '')}"><i class="bi bi-person-x-fill me-1"></i>${escapeHtml(reasonDisplay)}</span>`; absenceBadge = `<span class="badge bg-danger text-white me-1" style="font-size:0.65rem;" title="${escapeHtml(member.absence?.comment || '')}"><i class="bi bi-person-x-fill me-1"></i>${escapeHtml(reasonDisplay)}</span>`;
} }
const titleAbsence = member.is_absent ? "{% trans "Modifier ou annuler l'absence"|escapejs %}" : "{% trans "Marquer absent"|escapejs %}";
const titleUnassign = "{% trans 'Désassigner de cette équipe'|escapejs %}";
card.innerHTML = ` card.innerHTML = `
<div class="planning-member-info" title="${escapeHtml(member.name)}"> <div class="planning-member-info" title="${escapeHtml(member.name)}">
<span class="member-name-text fw-semibold">${escapeHtml(member.name)}</span> <span class="member-name-text fw-semibold">${escapeHtml(member.name)}</span>
@ -1484,10 +1485,10 @@ function createPlanningMemberCard(member, teamId, dateStr, canEdit) {
</div> </div>
${canEdit ? ` ${canEdit ? `
<div class="planning-card-actions"> <div class="planning-card-actions">
<button type="button" class="btn btn-sm btn-link p-0 text-muted btn-absence-toggle" title="${member.is_absent ? '{% trans "Modifier ou annuler l\'absence" %}' : '{% trans "Marquer absent" %}'}" onclick="openAbsenceModal(${member.id}, '${escapeHtml(member.name)}', '${dateStr}', ${member.is_absent ? 'true' : 'false'}, '${escapeHtml(member.absence?.reason || 'conge')}', '${escapeHtml(member.absence?.comment || '')}')"> <button type="button" class="btn btn-sm btn-link p-0 text-muted btn-absence-toggle" title="${titleAbsence}" onclick="openAbsenceModal(${member.id}, '${escapeHtml(member.name)}', '${dateStr}', ${member.is_absent ? 'true' : 'false'}, '${escapeHtml(member.absence?.reason || 'conge')}', '${escapeHtml(member.absence?.comment || '')}')">
<i class="bi ${member.is_absent ? 'bi-person-x-fill text-danger' : 'bi-person-check text-muted'}"></i> <i class="bi ${member.is_absent ? 'bi-person-x-fill text-danger' : 'bi-person-check text-muted'}"></i>
</button> </button>
<button type="button" class="btn btn-sm btn-link p-0 text-muted" title="{% trans 'Désassigner de cette équipe' %}" onclick="unassignMemberFromDate(${member.id}, '${dateStr}')"> <button type="button" class="btn btn-sm btn-link p-0 text-muted" title="${titleUnassign}" onclick="unassignMemberFromDate(${member.id}, '${dateStr}')">
<i class="bi bi-x fs-6"></i> <i class="bi bi-x fs-6"></i>
</button> </button>
</div>` : ''} </div>` : ''}
@ -1623,7 +1624,7 @@ function filterSidebarMembers() {
} }
function unassignMemberFromDate(memberId, dateStr) { function unassignMemberFromDate(memberId, dateStr) {
if (!confirm("{% trans 'Désassigner ce membre à partir de cette date ?' %}")) return; if (!confirm("{% trans 'Désassigner ce membre à partir de cette date ?'|escapejs %}")) return;
postJSON( postJSON(
'/contracts/teams/planning/assign/', '/contracts/teams/planning/assign/',
@ -1722,7 +1723,7 @@ function submitDuplicatePlanning() {
const copyAbsences = $('#dupCopyAbsences').is(':checked'); const copyAbsences = $('#dupCopyAbsences').is(':checked');
if (!sourceDate || !targetDate) { if (!sourceDate || !targetDate) {
$('#dupModalAlert').text("{% trans 'Veuillez renseigner les dates source et cible.' %}").removeClass('d-none'); $('#dupModalAlert').text("{% trans 'Veuillez renseigner les dates source et cible.'|escapejs %}").removeClass('d-none');
return; return;
} }