// =============================================================================
// FONCTIONS UTILITAIRES POUR LA GESTION DES ÉLÉMENTS
// =============================================================================
/**
* Active/désactive des éléments par leurs IDs
* @param {string[]} elementIds - Liste des IDs des éléments à activer
* @param {boolean} enabled - true pour activer, false pour désactiver
*/
function toggleElementsEnabled(elementIds, enabled = true) {
elementIds.forEach(id => {
const element = document.getElementById(id);
if (element) {
if (enabled) {
element.removeAttribute('disabled');
} else {
element.setAttribute('disabled', 'true');
}
}
});
}
/**
* Affiche/masque des conteneurs par leurs IDs
* @param {string[]} containerIds - Liste des IDs des conteneurs à afficher
* @param {boolean} visible - true pour afficher, false pour masquer
*/
function toggleContainersVisibility(containerIds, visible = true) {
containerIds.forEach(id => {
const container = document.getElementById(id);
if (container) {
if (visible) {
container.classList.remove('hidden');
} else {
container.classList.add('hidden');
}
}
});
}
/**
* Affiche le loading overlay avec un message personnalisé
* @param {string} message - Message à afficher
*/
function showLoadingOverlay(message = 'Chargement en cours...') {
document.getElementById('progress-text').textContent = message;
toggleContainersVisibility(['loading-overlay'], true);
}
/**
* Masque le loading overlay
*/
function hideLoadingOverlay() {
toggleContainersVisibility(['loading-overlay'], false);
}
/**
* Réinitialise un select et ajoute des options
* @param {string} selectId - ID du select
* @param {Object} options - Objet avec les options {value: text}
* @param {string} defaultText - Texte par défaut
*/
function populateSelect(selectId, options, defaultText = 'Sélectionner...') {
const select = document.getElementById(selectId);
if (select) {
select.innerHTML = ``;
Object.entries(options).forEach(([text, value]) => {
const option = document.createElement('option');
option.value = value;
option.textContent = text;
select.appendChild(option);
});
}
}
function populateCheckboxDropdown(optionsContainerId, options, filterType, labelId, selectionSet) {
const container = document.getElementById(optionsContainerId);
container.innerHTML = '';
selectionSet.clear(); // reset all
// Ajoute chaque option
options.forEach(option => {
const safeId = `${filterType}-${encodeURIComponent(option).replace(/[%\s]/g, '_')}`;
const label = document.createElement('label');
label.className = "flex items-center gap-2 cursor-pointer py-1";
label.innerHTML = `
${option}
`;
label.querySelector('input').addEventListener('change', function () {
if (this.checked) {
selectionSet.add(this.value);
} else {
selectionSet.delete(this.value);
}
// Gestion du label "Tous"
updateCheckboxDropdownLabel(filterType, labelId, selectionSet, options.length);
// Gestion du "Tous" global
const allBox = document.querySelector(`.${filterType}-checkbox[value="all"]`);
if (allBox && allBox.checked) allBox.checked = false;
// Si plus rien n'est coché, recoche "Tous"
if (selectionSet.size === 0 && allBox) allBox.checked = true;
applyFilters();
});
container.appendChild(label);
});
// Réinitialise le label
updateCheckboxDropdownLabel(filterType, labelId, selectionSet, options.length);
// Gestion de "Tous"
const allBox = document.querySelector(`.${filterType}-checkbox[value="all"]`);
if (allBox) {
allBox.addEventListener('change', function () {
if (this.checked) {
// Décoche tout le reste
selectionSet.clear();
container.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = false);
this.checked = true; // reste coché
updateCheckboxDropdownLabel(filterType, labelId, selectionSet, options.length);
applyFilters();
}
});
}
}
function updateCheckboxDropdownLabel(type, labelId, set, totalCount) {
const label = document.getElementById(labelId);
if (!set.size) {
label.textContent = type.charAt(0).toUpperCase() + type.slice(1) + " (Tous)";
} else if (set.size === 1) {
label.textContent = [...set][0];
} else {
label.textContent = `${type.charAt(0).toUpperCase() + type.slice(1)} (${set.size}/${totalCount})`;
}
}
function updateSelectedFilters(filterType, value, isChecked) {
if (isChecked) {
selectedFilters[filterType].add(value);
} else {
selectedFilters[filterType].delete(value);
}
}
function populateDaisyDropdown(menuId, options, labelId, onSelect) {
const menu = document.getElementById(menuId);
menu.innerHTML = '';
// Option "Tous"
const liAll = document.createElement('li');
liAll.innerHTML = `Tous`;
liAll.querySelector('a').onclick = e => {
e.preventDefault();
document.getElementById(labelId).textContent = "Type";
onSelect("");
};
menu.appendChild(liAll);
// Ajoute chaque option
options.forEach(opt => {
const li = document.createElement('li');
li.innerHTML = `${opt}`;
li.querySelector('a').onclick = e => {
e.preventDefault();
document.getElementById(labelId).textContent = opt;
onSelect(opt);
};
menu.appendChild(li);
});
}
function updateFilterLabel(filterType) {
const selectedCount = selectedFilters[filterType].size;
const labelElement = document.getElementById(`${filterType}-filter-label`);
if (selectedCount === 0) {
labelElement.textContent = `${filterType} (Tous)`;
} else {
labelElement.textContent = `${filterType} (${selectedCount} sélectionné${selectedCount > 1 ? 's' : ''})`;
}
}
/**
* Extrait les données du tableau selon un mapping
* @param {Object} mapping - Mapping des colonnes {columnName: propertyName}
* @returns {Array} Données extraites
*/
function extractTableData(mapping) {
const tbody = document.querySelector('#data-table tbody');
const rows = tbody.querySelectorAll('tr');
const data = [];
rows.forEach(row => {
const checkboxes = row.querySelectorAll('input[type="checkbox"]:checked');
if (checkboxes.length > 0) {
const rowData = {};
Object.entries(mapping).forEach(([columnName, propertyName]) => {
const cell = row.querySelector(`td[data-column="${columnName}"]`);
if (cell) {
if (columnName == "URL") {
rowData[propertyName] = cell.querySelector('a').getAttribute('href');
} else {
rowData[propertyName] = cell.textContent.trim();
}
}
});
data.push(rowData);
}
});
return data;
}
const TABS = {
'doc-table-tab': 'doc-table-tab-contents',
'requirements-tab': 'requirements-tab-contents',
'solutions-tab': 'solutions-tab-contents',
'query-tab': 'query-tab-contents'
};
/**
* Bascule l'affichage sur le nouveau tab
* @param {*} newTab
*/
function switchTab(newTab) {
// Remove active tab style from all tabs
Object.keys(TABS).forEach(tabId => {
const tabElement = document.getElementById(tabId);
if (tabElement) {
tabElement.classList.remove("tab-active");
}
});
// Hide all tab contents
Object.values(TABS).forEach(contentId => {
const contentElement = document.getElementById(contentId);
if (contentElement) {
contentElement.classList.add("hidden");
}
});
// Activate the new tab if it exists in the mapping
if (newTab in TABS) {
const newTabElement = document.getElementById(newTab);
const newContentElement = document.getElementById(TABS[newTab]);
if (newTabElement) newTabElement.classList.add("tab-active");
if (newContentElement) newContentElement.classList.remove("hidden");
}
}
/**
* Bascule l'affichage vers la tab uniquement si les requirements sont
*/
function enableTabSwitching() {
Object.keys(TABS).forEach(tabId => {
const tab = document.getElementById(tabId);
if (tab)
tab.classList.remove("tab-disabled");
})
}
/**
* Change l'état d'activation du number box de choix de nb de catégories.
*/
function debounceAutoCategoryCount(state) {
document.getElementById('category-count').disabled = state;
}