// ============================================================================= // 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; }