(function () { "use strict"; let analysisMatriciMap = {}; let analysisLoadedCache = {}; let analysisAssignedState = {}; let analysisSelectedState = {}; function loadAnalysisMatrixNames() { return $.ajax({ url: "get_matrici_db.php", method: "GET", dataType: "json", }) .done(function (data) { analysisMatriciMap = {}; (data.value || []).forEach(function (matrice) { analysisMatriciMap[String(matrice.IdMatrice)] = matrice.NomeMatrice || "#" + matrice.IdMatrice; }); applyAnalysisMatrixNames(); }) .fail(function () { analysisMatriciMap = {}; applyAnalysisMatrixNames(); }); } function applyAnalysisMatrixNames() { const modal = document.getElementById("analysisModal"); if (!modal) return; modal.querySelectorAll(".analysis-matrix-item").forEach((item) => { const matrixId = item.getAttribute("data-matrix-id"); const nameEl = item.querySelector(".analysis-matrix-name"); let matrixName = "No Matrix"; if (matrixId && matrixId !== "NO_MATRIX") { matrixName = analysisMatriciMap[String(matrixId)] || "#" + matrixId; } item.setAttribute("data-matrix-name", matrixName); if (nameEl) { nameEl.textContent = matrixName; } }); modal.querySelectorAll(".analysis-part-matrix-name").forEach((el) => { const matrixId = el.getAttribute("data-matrix-id"); if (!matrixId || matrixId === "NO_MATRIX") { el.textContent = "No Matrix"; return; } el.textContent = analysisMatriciMap[String(matrixId)] || "#" + matrixId; }); } function readInitialAssignedAnalyses() { const jsonEl = document.getElementById("analysisAssignedInitialData"); if (!jsonEl) { analysisAssignedState = {}; return; } try { analysisAssignedState = JSON.parse(jsonEl.textContent || "{}") || {}; } catch (e) { analysisAssignedState = {}; } } function getSelectedPartIds() { const modal = document.getElementById("analysisModal"); if (!modal) return []; return Array.from( modal.querySelectorAll(".analysis-part-checkbox:checked"), ).map((el) => String(el.value)); } function getCurrentSelectedAnalysisRecordKeys() { return Object.keys(analysisSelectedState).filter(function (key) { return analysisSelectedState[key] === true; }); } function renderAssignedAnalysesForPart(partId) { const container = document.getElementById( "analysisAssignedListPart" + partId, ); if (!container) return; const items = Array.isArray(analysisAssignedState[String(partId)]) ? analysisAssignedState[String(partId)] : []; if (!items.length) { container.innerHTML = ""; return; } container.innerHTML = items .map(function (item) { const recordKey = item.analysis_recordkey || ""; const title = item.analysis_name || "Unnamed analysis"; const method = item.analysis_method || ""; return `
${escapeHtml(title)}
${method ? `
${escapeHtml(method)}
` : ""}
`; }) .join(""); } function renderAssignedAnalysesForSelectedParts() { const modal = document.getElementById("analysisModal"); if (!modal) return; modal.querySelectorAll(".analysis-part-item").forEach(function (item) { const partId = item.getAttribute("data-part-id"); renderAssignedAnalysesForPart(partId); }); } function syncSelectedAnalysisRows() { const modal = document.getElementById("analysisModal"); if (!modal) return; modal .querySelectorAll(".analysis-analysis-item") .forEach(function (item) { const recordKey = item.getAttribute("data-recordkey") || ""; if (recordKey && analysisSelectedState[recordKey]) { item.classList.add("analysis-selected"); } else { item.classList.remove("analysis-selected"); } }); } function buildAnalysisPayloadFromRow(rowEl) { return { analysis_recordkey: rowEl.getAttribute("data-recordkey") || "", analysis_name: rowEl.getAttribute("data-analysis-name") || "", analysis_method: rowEl.getAttribute("data-analysis-method") || "", analysis_level: rowEl.getAttribute("data-analysis-level") || "", is_web_selectable: rowEl.getAttribute("data-web") === "1" ? 1 : 0, is_accredited: rowEl.getAttribute("data-accredited") === "1" ? 1 : 0, }; } function addAnalysisToLocalState(partId, payload, iddatadb, idmatrice) { const key = String(partId); if (!Array.isArray(analysisAssignedState[key])) { analysisAssignedState[key] = []; } const exists = analysisAssignedState[key].some(function (item) { return item.analysis_recordkey === payload.analysis_recordkey; }); if (!exists) { analysisAssignedState[key].push({ id: null, part_id: parseInt(partId, 10), iddatadb: iddatadb || null, idmatrice: idmatrice || null, analysis_recordkey: payload.analysis_recordkey, analysis_name: payload.analysis_name, analysis_method: payload.analysis_method, analysis_level: payload.analysis_level !== "" ? parseInt(payload.analysis_level, 10) : null, is_web_selectable: payload.is_web_selectable, is_accredited: payload.is_accredited, }); } } function removeAnalysisFromLocalState(partId, recordKey) { const key = String(partId); if (!Array.isArray(analysisAssignedState[key])) { return; } analysisAssignedState[key] = analysisAssignedState[key].filter( function (item) { return item.analysis_recordkey !== recordKey; }, ); } function saveAnalysisAssociation(partId, payload, callback) { const modal = document.getElementById("analysisModal"); if (!modal) return; const iddatadb = modal.querySelector("#analysisModalIddatadb")?.value || ""; const partItem = modal.querySelector( '.analysis-part-item[data-part-id="' + partId + '"]', ); const idmatrice = partItem ? partItem.getAttribute("data-matrix-id") || "" : ""; $.ajax({ url: "save_part_analysis.php", method: "POST", dataType: "json", data: { part_id: partId, iddatadb: iddatadb, idmatrice: idmatrice !== "NO_MATRIX" ? idmatrice : "", analysis_recordkey: payload.analysis_recordkey, analysis_name: payload.analysis_name, analysis_method: payload.analysis_method, analysis_level: payload.analysis_level, is_web_selectable: payload.is_web_selectable, is_accredited: payload.is_accredited, }, }) .done(function () { addAnalysisToLocalState( partId, payload, iddatadb, idmatrice !== "NO_MATRIX" ? idmatrice : null, ); renderAssignedAnalysesForPart(partId); if (typeof callback === "function") callback(true); }) .fail(function (xhr) { let message = "Error saving analysis association"; if (xhr && xhr.responseJSON && xhr.responseJSON.message) { message = xhr.responseJSON.message; } alert(message); if (typeof callback === "function") callback(false); }); } function deleteAnalysisAssociation(partId, recordKey, callback) { $.ajax({ url: "delete_part_analysis.php", method: "POST", dataType: "json", data: { part_id: partId, analysis_recordkey: recordKey, }, }) .done(function () { removeAnalysisFromLocalState(partId, recordKey); renderAssignedAnalysesForPart(partId); if (typeof callback === "function") callback(true); }) .fail(function (xhr) { let message = "Error deleting analysis association"; if (xhr && xhr.responseJSON && xhr.responseJSON.message) { message = xhr.responseJSON.message; } alert(message); if (typeof callback === "function") callback(false); }); } function setAnalysisLoadingState(isLoading) { const modal = document.getElementById("analysisModal"); if (!modal) return; const loadingEl = modal.querySelector("#analysisLoadingBox"); if (!loadingEl) return; if (isLoading) { loadingEl.classList.remove("d-none"); } else { loadingEl.classList.add("d-none"); } } function showAnalysisError(message) { const modal = document.getElementById("analysisModal"); if (!modal) return; const errorEl = modal.querySelector("#analysisErrorBox"); const emptyEl = modal.querySelector("#analysisEmptyBox"); const listEl = modal.querySelector("#analysisList"); if (listEl) listEl.innerHTML = ""; if (emptyEl) emptyEl.classList.add("d-none"); if (errorEl) { errorEl.textContent = message || "Error loading analyses"; errorEl.classList.remove("d-none"); } } function showAnalysisEmpty(message) { const modal = document.getElementById("analysisModal"); if (!modal) return; const errorEl = modal.querySelector("#analysisErrorBox"); const emptyEl = modal.querySelector("#analysisEmptyBox"); const listEl = modal.querySelector("#analysisList"); if (listEl) listEl.innerHTML = ""; if (errorEl) errorEl.classList.add("d-none"); if (emptyEl) { emptyEl.textContent = message || "No analyses found for this matrix"; emptyEl.classList.remove("d-none"); } } function escapeHtml(value) { return String(value ?? "") .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function renderAnalysesList(analyses) { const modal = document.getElementById("analysisModal"); if (!modal) return; const errorEl = modal.querySelector("#analysisErrorBox"); const emptyEl = modal.querySelector("#analysisEmptyBox"); const listEl = modal.querySelector("#analysisList"); if (!listEl) return; if (errorEl) errorEl.classList.add("d-none"); if (!Array.isArray(analyses) || analyses.length === 0) { showAnalysisEmpty("No analyses found for this matrix"); return; } if (emptyEl) emptyEl.classList.add("d-none"); listEl.innerHTML = analyses .map(function (item) { const recordKey = item.RecordKey || ""; const analysisName = item.NomeAnalisiTraduzione || item.NomeAnalisi || "Unnamed analysis"; const methodName = item.MetodoNome || ""; const selectable = item.SelezionabileSuWeb === true; const accredited = item.Accreditato === true; const level = item.Livello ?? ""; const searchText = ( analysisName + " " + methodName ).toLowerCase(); let badges = ""; if (selectable) { badges += 'Web'; } else { badges += 'Not web'; } if (accredited) { badges += 'Accredited'; } if (level !== "") { badges += 'Level ' + escapeHtml(level) + ""; } return `
${escapeHtml(analysisName)}
${methodName ? `
${escapeHtml(methodName)}
` : ""}
${badges}
`; }) .join(""); filterAnalysisList(); syncSelectedAnalysisRows(); } function filterAnalysisList() { const modal = document.getElementById("analysisModal"); if (!modal) return; const webOnlyEl = modal.querySelector("#analysisWebOnly"); const searchEl = modal.querySelector("#analysisSearchInput"); const items = modal.querySelectorAll(".analysis-analysis-item"); const emptyEl = modal.querySelector("#analysisEmptyBox"); const errorEl = modal.querySelector("#analysisErrorBox"); const webOnly = webOnlyEl ? webOnlyEl.checked : false; const searchValue = searchEl ? searchEl.value.trim().toLowerCase() : ""; let visibleCount = 0; items.forEach((item) => { const isWeb = item.getAttribute("data-web") === "1"; const searchText = ( item.getAttribute("data-search") || "" ).toLowerCase(); let visible = true; if (webOnly && !isWeb) { visible = false; } if (visible && searchValue && !searchText.includes(searchValue)) { visible = false; } item.style.display = visible ? "" : "none"; if (visible) { visibleCount++; } }); if (errorEl) { errorEl.classList.add("d-none"); } if (emptyEl) { if (items.length === 0) { emptyEl.textContent = "No analyses found for this matrix"; emptyEl.classList.remove("d-none"); } else if (visibleCount === 0) { emptyEl.textContent = "No analyses match the current filters"; emptyEl.classList.remove("d-none"); } else { emptyEl.classList.add("d-none"); } } } function loadAnalysesByMatrix(matrixId) { const modal = document.getElementById("analysisModal"); if (!modal) return; if (!matrixId || matrixId === "NO_MATRIX") { showAnalysisEmpty("No matrix selected"); return; } const listEl = modal.querySelector("#analysisList"); const errorEl = modal.querySelector("#analysisErrorBox"); const emptyEl = modal.querySelector("#analysisEmptyBox"); if (listEl) listEl.innerHTML = ""; if (errorEl) errorEl.classList.add("d-none"); if (emptyEl) { emptyEl.textContent = ""; emptyEl.classList.add("d-none"); } if (analysisLoadedCache[String(matrixId)]) { renderAnalysesList(analysisLoadedCache[String(matrixId)]); return; } setAnalysisLoadingState(true); $.ajax({ url: "get_analisi_matrice_filter.php", method: "GET", dataType: "json", data: { id_matrice: matrixId, }, }) .done(function (response) { const analyses = Array.isArray(response.value) ? response.value : []; analysisLoadedCache[String(matrixId)] = analyses; renderAnalysesList(analyses); }) .fail(function (xhr) { let message = "Error loading analyses"; if (xhr && xhr.responseJSON && xhr.responseJSON.error) { message = xhr.responseJSON.error; } showAnalysisError(message); }) .always(function () { setAnalysisLoadingState(false); }); } function updateSelectedPartsInfo() { const modal = document.getElementById("analysisModal"); if (!modal) return; const checked = modal.querySelectorAll( ".analysis-part-checkbox:checked", ); const ids = Array.from(checked).map((el) => el.value); const countEl = modal.querySelector("#analysisSelectedPartsCount"); const idsEl = modal.querySelector("#analysisSelectedPartsIds"); if (countEl) { countEl.textContent = `${ids.length} selected`; } if (idsEl) { idsEl.textContent = ids.length ? ids.join(", ") : "-"; } modal.querySelectorAll(".analysis-part-item").forEach((item) => { const checkbox = item.querySelector(".analysis-part-checkbox"); if (checkbox && checkbox.checked) { item.classList.add("part-checked"); } else { item.classList.remove("part-checked"); } }); } function selectPartsByMatrix(matrixId, matrixLabel) { const modal = document.getElementById("analysisModal"); if (!modal) return; const partItems = modal.querySelectorAll(".analysis-part-item"); const matrixLabelEl = modal.querySelector("#analysisCurrentMatrix"); partItems.forEach((item) => { const itemMatrixId = item.getAttribute("data-matrix-id"); const checkbox = item.querySelector(".analysis-part-checkbox"); item.classList.remove("matrix-active"); if (itemMatrixId === String(matrixId)) { item.classList.add("matrix-active"); if (checkbox) checkbox.checked = true; } else { if (checkbox) checkbox.checked = false; } }); if (matrixLabelEl) { matrixLabelEl.textContent = matrixLabel || "-"; } analysisSelectedState = {}; const selectedPartIds = getSelectedPartIds(); selectedPartIds.forEach(function (partId) { const assigned = Array.isArray( analysisAssignedState[String(partId)], ) ? analysisAssignedState[String(partId)] : []; assigned.forEach(function (item) { if (item.analysis_recordkey) { analysisSelectedState[item.analysis_recordkey] = true; } }); }); updateSelectedPartsInfo(); loadAnalysesByMatrix(matrixId); } function clearAnalysisSelection() { const modal = document.getElementById("analysisModal"); if (!modal) return; modal.querySelectorAll(".analysis-matrix-item").forEach((item) => { item.classList.remove("active"); }); modal.querySelectorAll(".analysis-part-item").forEach((item) => { item.classList.remove("matrix-active", "part-checked"); }); modal.querySelectorAll(".analysis-part-checkbox").forEach((cb) => { cb.checked = false; }); const matrixLabelEl = modal.querySelector("#analysisCurrentMatrix"); if (matrixLabelEl) matrixLabelEl.textContent = "-"; const webOnlyEl = modal.querySelector("#analysisWebOnly"); if (webOnlyEl) webOnlyEl.checked = false; const searchEl = modal.querySelector("#analysisSearchInput"); if (searchEl) searchEl.value = ""; const listEl = modal.querySelector("#analysisList"); if (listEl) listEl.innerHTML = ""; showAnalysisEmpty("Select a matrix to load analyses"); updateSelectedPartsInfo(); } function initAnalysisModal() { const modal = document.getElementById("analysisModal"); if (!modal) return; analysisLoadedCache = {}; analysisSelectedState = {}; readInitialAssignedAnalyses(); renderAssignedAnalysesForSelectedParts(); modal.querySelectorAll(".analysis-matrix-item").forEach((btn) => { btn.addEventListener("click", function () { modal .querySelectorAll(".analysis-matrix-item") .forEach((x) => x.classList.remove("active")); this.classList.add("active"); const matrixId = this.getAttribute("data-matrix-id"); const matrixLabel = this.getAttribute("data-matrix-name") || this.textContent.trim(); selectPartsByMatrix(matrixId, matrixLabel); }); }); modal.querySelectorAll(".analysis-part-checkbox").forEach((cb) => { cb.addEventListener("change", function () { updateSelectedPartsInfo(); }); }); const clearBtn = modal.querySelector("#analysisClearSelectionBtn"); if (clearBtn) { clearBtn.addEventListener("click", function () { clearAnalysisSelection(); }); } const webOnlyEl = modal.querySelector("#analysisWebOnly"); if (webOnlyEl) { webOnlyEl.addEventListener("change", function () { filterAnalysisList(); }); } const searchEl = modal.querySelector("#analysisSearchInput"); if (searchEl) { searchEl.addEventListener("input", function () { filterAnalysisList(); }); } modal.addEventListener("click", function (e) { const removeBtn = e.target.closest(".analysis-remove-btn"); if (removeBtn) { e.preventDefault(); e.stopPropagation(); const partId = removeBtn.getAttribute("data-part-id"); const recordKey = removeBtn.getAttribute("data-recordkey"); deleteAnalysisAssociation(partId, recordKey, function () { const stillUsed = Object.keys(analysisAssignedState).some( function (pid) { return ( Array.isArray(analysisAssignedState[pid]) && analysisAssignedState[pid].some( function (item) { return ( item.analysis_recordkey === recordKey ); }, ) ); }, ); if (!stillUsed) { delete analysisSelectedState[recordKey]; } syncSelectedAnalysisRows(); }); return; } const row = e.target.closest(".analysis-analysis-item"); if (!row) return; const selectedPartIds = getSelectedPartIds(); if (!selectedPartIds.length) { alert("Select at least one part first"); return; } const payload = buildAnalysisPayloadFromRow(row); if (!payload.analysis_recordkey) { alert("Invalid analysis record key"); return; } const recordKey = payload.analysis_recordkey; const alreadySelected = !!analysisSelectedState[recordKey]; if (alreadySelected) { selectedPartIds.forEach(function (partId) { deleteAnalysisAssociation(partId, recordKey); }); delete analysisSelectedState[recordKey]; syncSelectedAnalysisRows(); return; } let pending = selectedPartIds.length; let atLeastOneSaved = false; selectedPartIds.forEach(function (partId) { saveAnalysisAssociation(partId, payload, function (ok) { if (ok) atLeastOneSaved = true; pending--; if (pending <= 0 && atLeastOneSaved) { analysisSelectedState[recordKey] = true; syncSelectedAnalysisRows(); } }); }); }); const firstActiveMatrix = modal.querySelector( ".analysis-matrix-item.active", ); if (firstActiveMatrix) { const matrixId = firstActiveMatrix.getAttribute("data-matrix-id"); const matrixLabel = firstActiveMatrix.getAttribute("data-matrix-name") || firstActiveMatrix.textContent.trim(); selectPartsByMatrix(matrixId, matrixLabel); } else { updateSelectedPartsInfo(); } } // OPEN ANALYSIS MODAL FROM PARTS MODAL BUTTON $(document).on("click", ".open-analysis-modal-btn", function () { const partsModal = document.getElementById("partsModal"); const iddatadb = $("#partsModal").data("iddatadb"); if (!iddatadb) { console.error("iddatadb not found on #partsModal"); alert("iddatadb not found"); return; } $.ajax({ url: "modal_analysis.php", method: "GET", data: { iddatadb: iddatadb }, success: function (response) { $("#analysisModalContainer").html(response); const modalElement = document.getElementById("analysisModal"); if (!modalElement) { console.error("Analysis modal not found: #analysisModal"); return; } let modal = bootstrap.Modal.getInstance(modalElement); if (!modal) { modal = new bootstrap.Modal(modalElement, { backdrop: true, keyboard: true, focus: true, }); } loadAnalysisMatrixNames().always(function () { initAnalysisModal(); modal.show(); }); }, error: function (xhr, status, error) { console.error("Error loading analysis modal:", error); alert("Error loading analysis modal: " + error); }, }); }); // CLEANUP ON CLOSE $(document).on("hidden.bs.modal", "#analysisModal", function () { const modalElement = document.getElementById("analysisModal"); if (modalElement) { const modal = bootstrap.Modal.getInstance(modalElement); if (modal) modal.dispose(); } $("#analysisModalContainer").empty(); // keep parts modal alive, but remove extra backdrop leftovers $(".modal-backdrop").last().remove(); if ($("#partsModal").hasClass("show")) { $("body").addClass("modal-open"); } else { $("body").removeClass("modal-open").css("padding-right", ""); } }); })();