1
0
postauto/autopost/public/autopost.js

423 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// === Autopost client script ===
// --- CSRF global ---
(function () {
const meta = document.querySelector('meta[name="csrf-token"]');
const CSRF_TOKEN = meta ? meta.content : (window.__BOOTSTRAP__ && window.__BOOTSTRAP__.csrf) || '';
if (window.jQuery) {
$.ajaxSetup({ headers: { 'x-csrf-token': CSRF_TOKEN } });
}
})();
// --- XSS escape côté client ---
function esc(s) {
// ATTENTION: backtick échappé dans la classe de caractères: \`
return String(s).replace(/[&<>"'\`=]/g, c => ({
'&': '&amp;', '<': '&lt;', '>': '&gt;',
'"': '&quot;', "'": '&#39;', '\`': '&#96;', '=': '&#61;'
}[c]));
}
// --- Bootstrap values ---
const INITIAL_PAGE = (window.__BOOTSTRAP__ && window.__BOOTSTRAP__.page) || 1;
const INITIAL_TOTAL_PAGES= (window.__BOOTSTRAP__ && window.__BOOTSTRAP__.totalPages) || 1;
const PAGE_LIMIT = (window.__BOOTSTRAP__ && window.__BOOTSTRAP__.limit) || 100;
let currentPage = INITIAL_PAGE;
let currentTotalPages = INITIAL_TOTAL_PAGES;
let activeFilter = null; // number | null
let activeQuery = ''; // string
// --- Rendering: table ---
function updateTable(rows) {
var tbody = $('table tbody');
tbody.empty();
rows.forEach(function(row) {
var statusText = '';
var statusClass = '';
switch (parseInt(row.status)) {
case 0: statusText = 'EN ATTENTE'; statusClass = 'bg-cyan-500 text-black font-bold'; break;
case 1: statusText = 'ENVOI TERMINÉ'; statusClass = 'bg-green-300 text-black font-bold'; break;
case 2: statusText = 'ERREUR'; statusClass = 'bg-red-300 text-black font-bold'; break;
case 3: statusText = 'DEJA DISPONIBLE';statusClass = 'bg-pink-300 text-black font-bold'; break;
case 4: statusText = 'EN COURS'; statusClass = 'bg-yellow-300 text-black font-bold'; break;
default: statusText = 'INCONNU';
}
var logLink = (parseInt(row.status) === 1 || parseInt(row.status) === 2 || parseInt(row.status) === 4)
? ' | <a href="#" class="log-link text-blue-400 hover:underline" data-filename="' + esc(row.nom) + '">Log</a>'
: '';
var mediainfoLink = (parseInt(row.status) === 0 || parseInt(row.status) === 1 || parseInt(row.status) === 2)
? ' | <a href="#" class="mediainfo-link text-blue-400 hover:underline" data-filename="' + esc(row.nom) + '">Mediainfo</a>'
: '';
var dlLink = (parseInt(row.status) === 1)
? ' | <a href="/autopost/dl?name=' + encodeURIComponent(row.nom) + '" class="dl-link text-blue-400 hover:underline">DL</a>'
: '';
var tr =
'<tr id="row-' + row.id + '" data-status="' + row.status + '" class="odd:bg-gray-800 even:bg-gray-700">' +
'<td class="px-4 py-2 border border-gray-700 whitespace-nowrap">' + esc(row.nom) + '</td>' +
'<td class="px-4 py-2 border border-gray-700 status-text whitespace-nowrap ' + statusClass + '">' + statusText + '</td>' +
'<td class="px-4 py-2 border border-gray-700">' + row.id + '</td>' +
'<td class="px-4 py-2 border border-gray-700">' +
'<a href="#" class="edit-link text-blue-400 hover:underline" data-id="' + row.id + '" data-status="' + row.status + '">Editer</a> | ' +
'<a href="#" class="delete-link text-blue-400 hover:underline" data-id="' + row.id + '">Supprimer</a>' +
logLink + mediainfoLink + dlLink +
'</td>' +
'</tr>';
tbody.append(tr);
});
}
// --- Rendering: pagination ---
function renderPaginationHTML(page, totalPages) {
var prevDisabled = page <= 1;
var nextDisabled = page >= totalPages;
var h = '';
h += '<ul class="inline-flex items-center -space-x-px">';
h += '<li>';
if (prevDisabled) {
h += '<span class="px-3 py-2 ml-0 leading-tight text-gray-500 bg-gray-200 border border-gray-300 rounded-l-lg">Précédent</span>';
} else {
h += '<a href="/autopost/?page=' + (page - 1) + '" data-page="' + (page - 1) + '" class="px-3 py-2 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700">Précédent</a>';
}
h += '</li>';
h += '<li><span class="px-4 py-2 leading-tight text-gray-700 bg-white border border-gray-300">Page ' + page + ' sur ' + totalPages + '</span></li>';
h += '<li>';
if (nextDisabled) {
h += '<span class="px-3 py-2 leading-tight text-gray-500 bg-gray-200 border border-gray-300 rounded-r-lg">Suivant</span>';
} else {
h += '<a href="/autopost/?page=' + (page + 1) + '" data-page="' + (page + 1) + '" class="px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 rounded-r-lg hover:bg-gray-100 hover:text-gray-700">Suivant</a>';
}
h += '</li>';
h += '</ul>';
return h;
}
function updatePagination(page, totalPages) {
$('#pagination').html(renderPaginationHTML(page, totalPages));
}
// --- Data loading ---
function loadPage(p) {
const targetPage = Math.max(1, parseInt(p, 10) || 1);
const isFilter = activeFilter !== null;
const url = isFilter ? '/autopost/filter' : '/autopost/search';
const data = isFilter
? { status: activeFilter, page: targetPage, limit: PAGE_LIMIT }
: { q: activeQuery || '', page: targetPage, limit: PAGE_LIMIT };
$.ajax({
url: url,
type: 'GET',
data: data,
dataType: 'json',
success: function(resp) {
updateTable(resp.rows);
currentPage = resp.page;
currentTotalPages = resp.totalPages;
updatePagination(currentPage, currentTotalPages);
},
error: function(jqXHR, textStatus, errorThrown) {
if (textStatus !== 'abort') {
console.error('Erreur AJAX :', textStatus, errorThrown);
alert('Erreur lors du chargement de la page.');
}
}
});
}
// --- Long polling: refresh table when new mediainfo/log apparaît ---
(function () {
var lastVersion = null;
function poll() {
$.ajax({
url: '/autopost/updates',
type: 'GET',
data: { since: lastVersion || 0 },
timeout: 30000,
success: function (resp) {
if (resp && typeof resp.version === 'number') {
if (lastVersion === null) {
lastVersion = resp.version; // 1ère synchro: on se cale
} else if (resp.version > lastVersion) {
lastVersion = resp.version;
if (typeof loadPage === 'function') loadPage(currentPage || 1);
if (typeof updateStatsUI === 'function') {
$.getJSON('/autopost/stats', function (s) { if (s) updateStatsUI(s); });
}
}
}
setTimeout(poll, 100);
},
error: function () {
setTimeout(poll, 2000);
}
});
}
$(document).ready(poll);
})();
function updateStatsUI(s) {
$('.filter-card[data-status="0"] .tabular-nums').text(s.attente || 0);
$('.filter-card[data-status="1"] .tabular-nums').text(s.termine || 0);
$('.filter-card[data-status="2"] .tabular-nums').text(s.erreur || 0);
$('.filter-card[data-status="3"] .tabular-nums').text(s.deja || 0);
}
function refreshAfterChange() {
loadPage(currentPage || 1);
$.getJSON('/autopost/stats', function(s) { updateStatsUI(s); });
}
// --- DOM bindings ---
$(document).ready(function() {
// Recherche
let searchTimer = null;
$('#searchInput').on('keyup', function() {
clearTimeout(searchTimer);
let q = $(this).val();
searchTimer = setTimeout(function() {
activeQuery = q || '';
activeFilter = null; // on sort du mode filtre
$('.filter-card').removeClass('ring-4 ring-white/40');
loadPage(1); // charge page 1 avec pagination AJAX
toggleShowAllButton();
}, 300);
});
// Pagination: intercepter et paginer en AJAX
$(document).on('click', '#pagination a[data-page]', function(e) {
e.preventDefault();
const p = parseInt($(this).data('page'), 10);
if (!isNaN(p)) loadPage(p);
});
// Affichage/masquage du bouton "Tout afficher"
function toggleShowAllButton() {
if ($('.filter-card.ring-4').length === 0) {
$('#showAll').addClass('hidden');
} else {
$('#showAll').removeClass('hidden');
}
}
// Filtrage par clic sur une card
$(document).on('click', '.filter-card', function() {
const status = parseInt($(this).data('status'), 10);
$('.filter-card').removeClass('ring-4 ring-white/40');
$(this).addClass('ring-4 ring-white/40');
activeFilter = status;
activeQuery = ''; // on sort du mode recherche
loadPage(1); // page 1 du filtre
toggleShowAllButton();
});
// Bouton tout afficher
$(document).on('click', '#showAll', function() {
$('.filter-card').removeClass('ring-4 ring-white/40');
activeFilter = null;
activeQuery = $('#searchInput').val() || '';
loadPage(1);
toggleShowAllButton();
});
// Edition (ouvrir modale)
$(document).on('click', '.edit-link', function(e) {
e.preventDefault();
var releaseId = $(this).data('id');
var currentStatus = $(this).data('status');
$('#releaseId').val(releaseId);
$('#modalReleaseId').text(releaseId);
$('#statusSelect').val(currentStatus);
$('#editModal').removeClass('hidden').fadeIn();
});
// ---------- Confirmation de suppression (modale) ----------
var pendingDeleteId = null;
function openConfirmModal(id, name) {
pendingDeleteId = id;
$('#confirmItemName').text(name || ('ID ' + id));
$('#confirmDeleteModal').removeClass('hidden').fadeIn(120);
}
function closeConfirmModal() {
$('#confirmDeleteModal').fadeOut(120, function() {
$(this).addClass('hidden');
});
pendingDeleteId = null;
}
function showToast(msg) {
$('#toastMsg').text(msg || 'Opération effectuée');
$('#toast').removeClass('hidden').fadeIn(120);
setTimeout(function() {
$('#toast').fadeOut(150, function() { $(this).addClass('hidden'); });
}, 1800);
}
// Ouvrir la modale au clic sur "Supprimer"
$(document).on('click', '.delete-link', function(e) {
e.preventDefault();
var releaseId = $(this).data('id');
var name = $(this).closest('tr').find('td:first').text().trim();
openConfirmModal(releaseId, name);
});
// Boutons de la modale
$('#cancelDeleteBtn, #confirmDeleteClose').on('click', function() {
closeConfirmModal();
});
// Clic sur loverlay pour fermer
$('#confirmDeleteModal').on('click', function(e) {
if (e.target === this) { closeConfirmModal(); }
});
// Accessibilité clavier: Esc = fermer, Enter = confirmer
$(document).on('keydown', function(e) {
var modalVisible = !$('#confirmDeleteModal').hasClass('hidden');
if (!modalVisible) return;
if (e.key === 'Escape') { closeConfirmModal(); }
if (e.key === 'Enter') { $('#confirmDeleteBtn').click(); }
});
// Confirmer et supprimer via AJAX
$('#confirmDeleteBtn').on('click', function() {
if (!pendingDeleteId) return;
var releaseId = pendingDeleteId;
$.ajax({
url: '/autopost/delete/' + releaseId,
type: 'POST',
success: function() {
$('#row-' + releaseId)
.css('outline', '2px solid rgba(239,68,68,0.6)')
.fadeOut('300', function(){ $(this).remove(); });
showToast('Enregistrement supprimé');
},
error: function() {
alert('Erreur lors de la suppression.');
},
complete: function() {
closeConfirmModal();
}
});
});
// Affichage log
$(document).on('click', '.log-link', function(e) {
e.preventDefault();
var filename = $(this).data('filename');
$.ajax({
url: '/autopost/log',
type: 'GET',
data: { name: filename },
dataType: 'json',
success: function(data) {
$('#logContent').html(data.content);
$('#logModal').removeClass('hidden').fadeIn();
},
error: function() {
alert('Erreur lors du chargement du fichier log.');
}
});
});
// Affichage mediainfo
$(document).on('click', '.mediainfo-link', function(e) {
e.preventDefault();
var filename = $(this).data('filename');
$.ajax({
url: '/autopost/mediainfo',
type: 'GET',
data: { name: filename },
dataType: 'json',
success: function(data) {
$('#mediainfoContent').text(data.content);
$('#mediainfoModal').removeClass('hidden').fadeIn();
},
error: function() {
alert('Erreur lors du chargement du fichier mediainfo.');
}
});
});
// Fermeture modales (croix + clic overlay)
$('.close').click(function() {
$(this).closest('.fixed').fadeOut(function() {
$(this).addClass('hidden');
});
});
$('.fixed').click(function(e) {
if (e.target === this) {
$(this).fadeOut(function() {
$(this).addClass('hidden');
});
}
});
// Edition: submit
$('#editForm').submit(function(e) {
e.preventDefault();
var releaseId = $('#releaseId').val();
var newStatus = $('#statusSelect').val();
$.ajax({
url: '/autopost/edit/' + releaseId,
type: 'POST',
data: { status: newStatus },
success: function() {
var statusText = '';
var statusClass = '';
switch (parseInt(newStatus)) {
case 0: statusText = 'EN ATTENTE'; statusClass = 'bg-cyan-500 text-black font-bold'; break;
case 1: statusText = 'ENVOI TERMINÉ'; statusClass = 'bg-green-300 text-black font-bold'; break;
case 2: statusText = 'ERREUR'; statusClass = 'bg-red-300 text-black font-bold'; break;
case 3: statusText = 'DEJA DISPONIBLE';statusClass = 'bg-pink-300 text-black font-bold'; break;
case 4: statusText = 'EN COURS'; statusClass = 'bg-yellow-300 text-black font-bold'; break;
default: statusText = 'INCONNU';
}
var row = $('#row-' + releaseId);
row.find('.status-text')
.removeClass('bg-cyan-500 bg-green-300 bg-red-300 bg-pink-300 bg-yellow-300')
.addClass(statusClass)
.text(statusText);
$('#editModal').fadeOut(function() {
$(this).addClass('hidden');
});
},
error: function() {
alert('Erreur lors de la mise à jour.');
}
});
});
// Bouton copier Mediainfo
$('#copyMediainfoBtn').on('click', function() {
const content = document.getElementById('mediainfoContent').textContent;
navigator.clipboard.writeText(content).then(() => {
this.textContent = '✅ Copié !';
setTimeout(() => this.textContent = '📋 Copier JSON', 2000);
}).catch(function(err) {
alert('Erreur lors de la copie : ' + err);
});
});
});