Improved PDF and MD export
This commit is contained in:
parent
521c782c42
commit
57204e9a67
@ -593,71 +593,82 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
updateProtocolData();
|
||||
|
||||
// Use community name if available, otherwise default
|
||||
const communityName = protocol.metadata.communityName || "Community";
|
||||
let markdown = `# ${communityName} Dispute Protocol\n\n`;
|
||||
|
||||
// Include protocol summary if available
|
||||
if (protocol.metadata.summary) {
|
||||
markdown += `${protocol.metadata.summary}\n\n`;
|
||||
markdown += '---\n\n';
|
||||
}
|
||||
|
||||
// Include template information if a template was used
|
||||
if (protocol.templateTitle) {
|
||||
markdown += `**Template Used:** ${protocol.templateTitle}\n\n`;
|
||||
markdown += '---\n\n';
|
||||
}
|
||||
|
||||
// Loop through the stages in order
|
||||
stageHeaders.forEach(header => {
|
||||
const stageId = header.getAttribute('data-stage');
|
||||
const stageName = header.querySelector('h2').textContent;
|
||||
try {
|
||||
// Use community name if available, otherwise default
|
||||
const communityName = protocol.metadata.communityName || "Community";
|
||||
let markdown = `# ${communityName}\n# Dispute Protocol\n\n`;
|
||||
|
||||
let stageContent = '';
|
||||
let hasContent = false;
|
||||
// Include protocol summary if available
|
||||
if (protocol.metadata.summary) {
|
||||
markdown += `${protocol.metadata.summary}\n\n`;
|
||||
markdown += '---\n\n';
|
||||
}
|
||||
|
||||
// Get components for this stage
|
||||
const stageComponents = protocol.stages[stageId];
|
||||
if (stageComponents) {
|
||||
// Loop through components
|
||||
for (const componentId in stageComponents) {
|
||||
const componentCard = document.getElementById(`component-${componentId}`);
|
||||
if (componentCard) {
|
||||
const componentName = componentCard.querySelector('h3').textContent;
|
||||
|
||||
let componentContent = '';
|
||||
let componentHasContent = false;
|
||||
|
||||
// Loop through fields
|
||||
for (const fieldId in stageComponents[componentId]) {
|
||||
const fieldValue = stageComponents[componentId][fieldId];
|
||||
// Template information removed as requested
|
||||
|
||||
// Loop through the stages in order
|
||||
stageHeaders.forEach(header => {
|
||||
const stageId = header.getAttribute('data-stage');
|
||||
const stageName = header.querySelector('h2').textContent;
|
||||
|
||||
let stageContent = '';
|
||||
let hasContent = false;
|
||||
|
||||
// Get components for this stage
|
||||
const stageComponents = protocol.stages[stageId];
|
||||
if (stageComponents) {
|
||||
// Loop through components
|
||||
for (const componentId in stageComponents) {
|
||||
const componentCard = document.getElementById(`component-${componentId}`);
|
||||
if (componentCard) {
|
||||
const componentName = componentCard.querySelector('h3').textContent;
|
||||
|
||||
// Skip empty fields
|
||||
if (fieldValue && fieldValue.trim()) {
|
||||
const fieldLabel = document.querySelector(`label[for="${fieldId}"]`).textContent;
|
||||
componentContent += `#### ${fieldLabel}\n\n${fieldValue}\n\n`;
|
||||
componentHasContent = true;
|
||||
hasContent = true;
|
||||
let componentContent = '';
|
||||
let componentHasContent = false;
|
||||
|
||||
// Loop through fields
|
||||
for (const fieldId in stageComponents[componentId]) {
|
||||
const fieldValue = stageComponents[componentId][fieldId];
|
||||
|
||||
// Skip empty fields
|
||||
if (fieldValue && fieldValue.trim()) {
|
||||
// Skip the field label, just add the content
|
||||
componentContent += `${fieldValue}\n\n`;
|
||||
componentHasContent = true;
|
||||
hasContent = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Only add component if it has content
|
||||
if (componentHasContent) {
|
||||
stageContent += `### ${componentName}\n\n${componentContent}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Only add component if it has content
|
||||
if (componentHasContent) {
|
||||
stageContent += `### ${componentName}\n\n${componentContent}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only add stage if it has content
|
||||
if (hasContent) {
|
||||
// Get the stage section ID (e.g., "Intake")
|
||||
const stageSection = header.closest('.stage-section');
|
||||
const stageSectionId = stageSection ? stageSection.id.replace('stage-', '') : '';
|
||||
const stageSectionTitle = stageSectionId ? stageSectionId.charAt(0).toUpperCase() + stageSectionId.slice(1) : '';
|
||||
|
||||
// Use just the section title to avoid duplication
|
||||
if (stageSectionTitle) {
|
||||
markdown += `## ${stageSectionTitle}\n\n${stageContent}`;
|
||||
} else {
|
||||
markdown += `## ${stageName}\n\n${stageContent}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Only add stage if it has content
|
||||
if (hasContent) {
|
||||
markdown += `## ${stageName}\n\n${stageContent}`;
|
||||
}
|
||||
});
|
||||
|
||||
// Create and download the file
|
||||
downloadFile('community_dispute_protocol.md', markdown);
|
||||
// Create and download the file
|
||||
downloadFile('community_dispute_protocol.md', markdown);
|
||||
} catch (error) {
|
||||
console.error('Error generating Markdown:', error);
|
||||
alert('Failed to generate Markdown. Please try again.');
|
||||
}
|
||||
});
|
||||
|
||||
// Export to PDF
|
||||
@ -666,138 +677,148 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
updateProtocolData();
|
||||
|
||||
// Create a styled HTML version for PDF export
|
||||
const { jsPDF } = window.jspdf;
|
||||
const doc = new jsPDF();
|
||||
|
||||
let yPos = 20;
|
||||
|
||||
// Use community name if available, otherwise default
|
||||
const communityName = protocol.metadata.communityName || "Community";
|
||||
|
||||
// Add title
|
||||
doc.setFontSize(18);
|
||||
doc.text(`${communityName} Dispute Protocol`, 105, yPos, { align: 'center' });
|
||||
yPos += 15;
|
||||
|
||||
// Add protocol summary if available
|
||||
if (protocol.metadata.summary) {
|
||||
doc.setFontSize(12);
|
||||
const summaryLines = doc.splitTextToSize(protocol.metadata.summary, 180);
|
||||
doc.text(summaryLines, 14, yPos);
|
||||
yPos += summaryLines.length * 7 + 8;
|
||||
}
|
||||
|
||||
// Add template info if available
|
||||
if (protocol.templateTitle) {
|
||||
doc.setFontSize(10);
|
||||
doc.text(`Template Used: ${protocol.templateTitle}`, 14, yPos);
|
||||
yPos += 10;
|
||||
}
|
||||
|
||||
// Loop through the stages
|
||||
stageHeaders.forEach(header => {
|
||||
const stageId = header.getAttribute('data-stage');
|
||||
const stageName = header.querySelector('h2').textContent;
|
||||
|
||||
let stageHasContent = false;
|
||||
let stageStartYPos = yPos;
|
||||
|
||||
// Save current position to add stage heading later if content is found
|
||||
if (yPos > 250) {
|
||||
doc.addPage();
|
||||
stageStartYPos = 20;
|
||||
yPos = 20;
|
||||
try {
|
||||
// Check if jspdf is properly loaded
|
||||
if (typeof window.jspdf === 'undefined') {
|
||||
console.error('jsPDF library not loaded properly');
|
||||
alert('PDF export is currently unavailable. The required library failed to load.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip stage heading for now - we'll add it if the stage has content
|
||||
let currentYPos = stageStartYPos + 10; // Space for the heading
|
||||
// Create a styled HTML version for PDF export
|
||||
const { jsPDF } = window.jspdf;
|
||||
const doc = new jsPDF();
|
||||
|
||||
// Get components for this stage
|
||||
const stageComponents = protocol.stages[stageId];
|
||||
if (stageComponents) {
|
||||
// Loop through components
|
||||
for (const componentId in stageComponents) {
|
||||
const componentCard = document.getElementById(`component-${componentId}`);
|
||||
if (componentCard) {
|
||||
let componentHasContent = false;
|
||||
let componentStartYPos = currentYPos;
|
||||
|
||||
// Check for page break
|
||||
if (currentYPos > 250) {
|
||||
doc.addPage();
|
||||
componentStartYPos = 20;
|
||||
currentYPos = 20;
|
||||
}
|
||||
|
||||
// Skip component heading for now - add if it has content
|
||||
const componentFieldStartYPos = componentStartYPos + 8;
|
||||
let fieldYPos = componentFieldStartYPos;
|
||||
|
||||
const componentName = componentCard.querySelector('h3').textContent;
|
||||
// Set consistent text width parameters
|
||||
const margins = {
|
||||
left: 14,
|
||||
right: 14,
|
||||
pageWidth: 210, // A4 width in mm (portrait)
|
||||
width: 182 // We'll use this as the consistent text width - should be pageWidth - left - right
|
||||
};
|
||||
|
||||
let yPos = 20;
|
||||
|
||||
// Use community name if available, otherwise default
|
||||
const communityName = protocol.metadata.communityName || "Community";
|
||||
|
||||
// Add title with line break
|
||||
doc.setFontSize(18);
|
||||
doc.text(`${communityName}\nDispute Protocol`, 105, yPos, { align: 'center' });
|
||||
yPos += 25;
|
||||
|
||||
// Page width indicator removed
|
||||
|
||||
// Add protocol summary if available
|
||||
if (protocol.metadata.summary) {
|
||||
doc.setFontSize(12);
|
||||
const summaryLines = doc.splitTextToSize(protocol.metadata.summary, margins.width);
|
||||
doc.text(summaryLines, margins.left, yPos);
|
||||
yPos += summaryLines.length * 7 + 8;
|
||||
}
|
||||
|
||||
// Template information removed as requested
|
||||
|
||||
// Set up direct rendering approach to avoid duplication
|
||||
const sectionsToProcess = [];
|
||||
|
||||
// Find all unique stage sections with content
|
||||
document.querySelectorAll('.stage-section').forEach(section => {
|
||||
const sectionId = section.id.replace('stage-', '');
|
||||
const sectionTitle = sectionId.charAt(0).toUpperCase() + sectionId.slice(1);
|
||||
|
||||
const componentsWithContent = [];
|
||||
|
||||
// Look for components with content in this section
|
||||
section.querySelectorAll('.component-card').forEach(componentCard => {
|
||||
const componentId = componentCard.id.replace('component-', '');
|
||||
|
||||
// Check if this component has content in the protocol data
|
||||
const stageId = section.id.replace('stage-', '');
|
||||
if (protocol.stages[stageId] &&
|
||||
protocol.stages[stageId][componentId] &&
|
||||
Object.keys(protocol.stages[stageId][componentId]).length > 0) {
|
||||
|
||||
componentsWithContent.push({
|
||||
id: componentId,
|
||||
element: componentCard,
|
||||
name: componentCard.querySelector('h3').textContent
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Only include sections that have components with content
|
||||
if (componentsWithContent.length > 0) {
|
||||
sectionsToProcess.push({
|
||||
id: sectionId,
|
||||
title: sectionTitle,
|
||||
components: componentsWithContent
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Process each section directly to avoid duplication
|
||||
sectionsToProcess.forEach(section => {
|
||||
// Add page break if needed
|
||||
if (yPos > 250) {
|
||||
doc.addPage();
|
||||
yPos = 20;
|
||||
}
|
||||
|
||||
// Add section header only once (e.g., "Intake")
|
||||
doc.setFontSize(18);
|
||||
doc.text(section.title, margins.left, yPos);
|
||||
yPos += 15;
|
||||
|
||||
// Process components in this section
|
||||
section.components.forEach(component => {
|
||||
// Add page break if needed
|
||||
if (yPos > 250) {
|
||||
doc.addPage();
|
||||
yPos = 20;
|
||||
}
|
||||
|
||||
// Add component heading
|
||||
doc.setFontSize(14);
|
||||
doc.text(component.name, margins.left, yPos);
|
||||
yPos += 8;
|
||||
|
||||
// Get fields for this component
|
||||
const stageId = section.id;
|
||||
const componentId = component.id;
|
||||
|
||||
if (protocol.stages[stageId] && protocol.stages[stageId][componentId]) {
|
||||
// Loop through fields
|
||||
for (const fieldId in stageComponents[componentId]) {
|
||||
const fieldValue = stageComponents[componentId][fieldId];
|
||||
for (const fieldId in protocol.stages[stageId][componentId]) {
|
||||
const fieldValue = protocol.stages[stageId][componentId][fieldId];
|
||||
|
||||
// Skip empty fields
|
||||
if (fieldValue && fieldValue.trim()) {
|
||||
const fieldLabel = document.querySelector(`label[for="${fieldId}"]`).textContent;
|
||||
|
||||
// Add page break if needed
|
||||
if (fieldYPos > 250) {
|
||||
if (yPos > 250) {
|
||||
doc.addPage();
|
||||
fieldYPos = 20;
|
||||
yPos = 20;
|
||||
}
|
||||
|
||||
// We have content - if this is the first content in the component,
|
||||
// add the component heading
|
||||
if (!componentHasContent) {
|
||||
componentHasContent = true;
|
||||
stageHasContent = true;
|
||||
|
||||
// If this is the first content in the stage, add the stage heading
|
||||
if (!stageHasContent) {
|
||||
doc.setFontSize(16);
|
||||
doc.text(stageName, 14, stageStartYPos);
|
||||
}
|
||||
|
||||
// Add component heading
|
||||
doc.setFontSize(14);
|
||||
doc.text(componentName, 14, componentStartYPos);
|
||||
}
|
||||
|
||||
// Add field heading
|
||||
// Format field content with larger font size (12)
|
||||
doc.setFontSize(12);
|
||||
doc.text(fieldLabel, 14, fieldYPos);
|
||||
fieldYPos += 6;
|
||||
|
||||
// Split the text into lines to handle wrapping
|
||||
const textLines = doc.splitTextToSize(fieldValue, 180);
|
||||
|
||||
// Add field content
|
||||
doc.setFontSize(10);
|
||||
doc.text(textLines, 14, fieldYPos);
|
||||
fieldYPos += textLines.length * 5 + 8;
|
||||
// Use consistent width for all text
|
||||
const textLines = doc.splitTextToSize(fieldValue, margins.width);
|
||||
doc.text(textLines, margins.left, yPos);
|
||||
yPos += textLines.length * 6 + 8; // Slightly increase spacing for larger font
|
||||
}
|
||||
}
|
||||
|
||||
// Update current Y position if component had content
|
||||
if (componentHasContent) {
|
||||
currentYPos = fieldYPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Update the overall Y position if stage had content
|
||||
if (stageHasContent) {
|
||||
yPos = currentYPos;
|
||||
}
|
||||
});
|
||||
|
||||
// Save the PDF
|
||||
doc.save('community_dispute_protocol.pdf');
|
||||
// Save the PDF
|
||||
doc.save('community_dispute_protocol.pdf');
|
||||
} catch (error) {
|
||||
console.error('Error generating PDF:', error);
|
||||
alert('Failed to generate PDF. Please try again or use another export format.');
|
||||
}
|
||||
});
|
||||
|
||||
// Export to JSON
|
||||
|
Loading…
x
Reference in New Issue
Block a user