No custom constraints defined.
";
}
appState.customConstraints.forEach(function(constraint) {
var item = document.createElement("div");
item.className = "fpc-constraint-item";
item.innerHTML = `
${constraint.elementName}: ${constraint.min}..${constraint.max} (${constraint.notes.substring(0, 40)}...)
`;
constraintListDiv.appendChild(item);
});
}
function renderDashboardTab() {
var baseResourceName = appState.baseResource;
var baseElements = baseResourceData[baseResourceName] || [];
var constraints = appState.customConstraints;
// Metadata Display
dispProfileName.textContent = appState.profileName;
dispBaseResource.textContent = baseResourceName;
dispProfileDate.textContent = appState.profileDate;
dispTotalConstraints.textContent = constraints.length;
// Render Table
tableBody.innerHTML = "";
// Combine base elements and constraints, ensuring all base elements are listed
baseElements.forEach(function(baseEl) {
var constraint = constraints.find(function(c) {
return c.elementName === baseEl.name;
});
var profileMin = constraint ? constraint.min : baseEl.baseMin;
var profileMax = constraint ? constraint.max : baseEl.baseMax;
var profileType = constraint ? (constraint.type || baseEl.baseType) : baseEl.baseType;
var notes = constraint ? constraint.notes : '';
// Check for override
var minOverride = profileMin !== baseEl.baseMin;
var maxOverride = profileMax !== baseEl.baseMax;
var typeOverride = profileType !== baseEl.baseType;
var minClass = minOverride ? 'fpc-override' : 'fpc-cardinality';
var maxClass = maxOverride ? 'fpc-override' : 'fpc-cardinality';
var typeClass = typeOverride ? 'fpc-override' : '';
var tr = document.createElement("tr");
tr.innerHTML = `
${baseEl.name} |
${baseEl.baseMin}..${baseEl.baseMax} |
${profileMin}..${profileMax} |
${baseEl.baseType} |
${profileType} |
${baseEl.baseDesc} |
${notes} |
`;
tableBody.appendChild(tr);
});
if (baseElements.length === 0) {
tableBody.innerHTML = "
| ERROR: No base elements found for the selected resource. |
";
}
}
// --- Event Handlers ---
// Update State on Resource Change
baseResourceSelect.addEventListener('change', function() {
appState.baseResource = baseResourceSelect.value;
loadBaseElements(appState.baseResource);
// Note: For a real tool, you might clear constraints here, but we keep them for the mock.
});
// Update Dashboard Button
updateBtn.addEventListener("click", function() {
appState.profileName = profileNameInput.value || "Untitled Profile";
appState.profileDate = profileDateInput.value || new Date().toISOString().split('T')[0];
appState.baseResource = baseResourceSelect.value;
saveState();
renderDashboardTab();
showTab(1); // Switch to Dashboard
});
// Add Constraint
addConstraintBtn.addEventListener("click", function() {
var elementName = elementSelect.value;
var min = minInput.value.trim();
var max = maxInput.value.trim();
var type = typeInput.value.trim();
var notes = notesInput.value.trim();
if (!elementName || !min || !max) {
alert("Please select an Element Name and define Min/Max Cardinality.");
return;
}
if (appState.customConstraints.some(function(c) { return c.elementName === elementName; })) {
alert("A constraint for this element already exists. Remove the old one first.");
return;
}
var newId = appState.customConstraints.length > 0 ? appState.customConstraints[appState.customConstraints.length - 1].id + 1 : 1;
var newConstraint = {
id: newId,
elementName: elementName,
min: min,
max: max,
type: type,
notes: notes
};
appState.customConstraints.push(newConstraint);
saveState();
renderConfigTab();
// Clear form (except selects)
minInput.value = "";
maxInput.value = "";
typeInput.value = "";
notesInput.value = "";
elementSelect.value = "";
});
// Remove Constraint (Event Delegation)
toolContainer.addEventListener("click", function(e) {
if (e.target.classList.contains("fpc-remove-btn")) {
var id = parseInt(e.target.dataset.id);
appState.customConstraints = appState.customConstraints.filter(function(c) { return c.id !== id; });
saveState();
renderConfigTab();
}
});
// --- PDF Download ---
pdfBtn.addEventListener("click", function() {
var jsPDF = window.jspdf.jsPDF;
var titleSlug = profileNameInput.value.replace(/[^a-zA-Z0-9\s]/g, '').replace(/\s/g, '_').substring(0, 30) || 'FHIR_Profile';
var fileName = `${titleSlug}.pdf`;
// Temporarily adjust minimum table width for PDF quality
var table = document.getElementById('fpc-profile-table');
var originalMinWidth = table.style.minWidth;
table.style.minWidth = '1200px';
html2canvas(exportArea, {
scale: 2,
useCORS: true,
backgroundColor: '#ffffff'
}).then(function(canvas) {
// Restore styles
table.style.minWidth = originalMinWidth;
var imgData = canvas.toDataURL('image/png');
var doc = new jsPDF({
orientation: 'l', // Landscape is better for wide tables
unit: 'pt',
format: 'a3' // Use A3 for maximum table fit
});
var pdfWidth = doc.internal.pageSize.getWidth();
var pdfHeight = doc.internal.pageSize.getHeight();
var imgProps = doc.getImageProperties(imgData);
var imgWidth = imgProps.width;
var imgHeight = imgProps.height;
var margin = 40;
var usableWidth = pdfWidth - (2 * margin);
var ratio = usableWidth / imgWidth;
var scaledHeight = imgHeight * ratio;
// Handle multi-page if content exceeds page height
if (scaledHeight > pdfHeight - (2 * margin)) {
var pageHeight = pdfHeight - (2 * margin);
var heightLeft = scaledHeight;
var position = 0;
while (heightLeft > 0) {
doc.addImage(imgData, 'PNG', margin, position + margin, usableWidth, scaledHeight);
heightLeft -= pageHeight;
position -= pageHeight;
if (heightLeft > 0) {
doc.addPage();
}
}
} else {
// Single page
doc.addImage(imgData, 'PNG', margin, margin, usableWidth, scaledHeight);
}
doc.save(fileName);
}).catch(function(err) {
// Restore styles even if PDF fails
table.style.minWidth = originalMinWidth;
console.error("FPC PDF Error:", err);
// alert("An error occurred while generating the PDF."); // Per spec
});
});
// --- Local Storage ---
function saveState() {
try {
localStorage.setItem("fpcAppState", JSON.stringify(appState));
} catch (e) { console.warn("FPC: Could not save state."); }
}
function loadState() {
try {
var storedState = localStorage.getItem("fpcAppState");
if (storedState) appState = JSON.parse(storedState);
} catch (e) { console.warn("FPC: Could not load state."); }
}
// --- Initial Load ---
loadState();
renderConfigTab();
renderDashboardTab();
showTab(0);
});