Spaces:
Sleeping
Sleeping
| // ============================================================================= | |
| // 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 = `<option value="">${defaultText}</option>`; | |
| 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 = ` | |
| <input type="checkbox" class="${filterType}-checkbox option-checkbox" id="${safeId}" value="${option}"> | |
| <span>${option}</span> | |
| `; | |
| 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 = `<a data-value="">Tous</a>`; | |
| 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 = `<a data-value="${opt}">${opt}</a>`; | |
| 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; | |
| } | |