None specified.
`;
const listItems = items.map(line => `
${line.trim().replace(/^\d+\.\s*/, '')}`).join('');
return `<${type}>${listItems}${type}>`;
}
function generateSOP() {
const sopTitle = document.getElementById('sopTitle').value || 'Untitled SOP';
const outputHTML = `
1.0 Purpose
${document.getElementById('sopPurpose').value.replace(/\n/g, '
') || 'Not specified.'}
2.0 Scope
${document.getElementById('sopScope').value.replace(/\n/g, '
') || 'Not specified.'}
3.0 Responsibilities
${parseTextToHtmlList(document.getElementById('sopResponsibilities').value, 'ul')}
4.0 Materials & Equipment
${parseTextToHtmlList(document.getElementById('sopMaterials').value, 'ul')}
5.0 Procedure
${parseTextToHtmlList(document.getElementById('sopProcedure').value, 'ol')}
`;
document.getElementById('output-display').innerHTML = outputHTML;
document.getElementById('output-title').textContent = sopTitle;
formContainer.style.display = 'none';
document.getElementById('tab-container').style.display = 'none';
navButtons.style.display = 'none';
outputSection.classList.remove('hidden');
}
function downloadPDF() {
const { jsPDF } = window.jspdf;
if (!downloadBtn) return;
downloadBtn.textContent = 'Generating Document...';
downloadBtn.disabled = true;
try {
const sopTitle = document.getElementById('sopTitle').value || 'Untitled SOP';
const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
const margin = 20;
const pageWidth = doc.internal.pageSize.getWidth();
const pageHeight = doc.internal.pageSize.getHeight();
const effectiveDate = new Date().toLocaleDateString('en-US');
const docId = `SOP-${Date.now().toString().slice(-6)}`;
let yPos = 0;
let pageNum = 1;
const addHeader = () => {
doc.setFont('Helvetica', 'bold');
doc.setFontSize(16);
doc.text(sopTitle, pageWidth / 2, margin, { align: 'center' });
doc.setFontSize(9);
doc.setFont('Helvetica', 'normal');
doc.text(`Document ID: ${docId}`, margin, margin + 10);
doc.text(`Version: 1.0`, margin, margin + 14);
doc.text(`Effective Date: ${effectiveDate}`, margin, margin + 18);
doc.setDrawColor(150);
doc.line(margin, margin + 22, pageWidth - margin, margin + 22);
yPos = margin + 30;
};
const addFooter = () => {
doc.setFont('Helvetica', 'normal');
doc.setFontSize(9);
doc.text(`Page ${pageNum}`, pageWidth / 2, pageHeight - 10, { align: 'center' });
};
const checkPageBreak = (heightNeeded) => {
if (yPos + heightNeeded > pageHeight - 15) {
addFooter();
doc.addPage();
pageNum++;
addHeader();
addFooter();
}
};
const addSection = (title, content, isOrderedList = false) => {
const lines = doc.splitTextToSize(content.replace(/^\d+\.\s*/gm, ''), pageWidth - margin * 2 - (isOrderedList ? 5 : 0));
checkPageBreak(12 + lines.length * 5);
doc.setFont('Helvetica', 'bold');
doc.setFontSize(12);
doc.text(title, margin, yPos);
yPos += 7;
doc.setFont('Helvetica', 'normal');
doc.setFontSize(10);
if (isOrderedList) {
const items = content.split('\n').filter(line => line.trim() !== '');
items.forEach((item, index) => {
const itemLines = doc.splitTextToSize(item.trim().replace(/^\d+\.\s*/, ''), pageWidth - margin * 2 - 8);
checkPageBreak(itemLines.length * 5 + 2);
doc.text(`${index + 1}.`, margin, yPos);
doc.text(itemLines, margin + 8, yPos);
yPos += itemLines.length * 5 + 2;
});
} else if (content.includes('\n')) { // Unordered list
const items = content.split('\n').filter(line => line.trim() !== '');
items.forEach(item => {
const itemLines = doc.splitTextToSize(item.trim(), pageWidth - margin * 2 - 8);
checkPageBreak(itemLines.length * 5 + 2);
doc.text(`•`, margin + 3, yPos);
doc.text(itemLines, margin + 8, yPos);
yPos += itemLines.length * 5 + 2;
});
}
else { // Paragraph
doc.text(lines, margin, yPos);
yPos += lines.length * 5 + 5;
}
};
addHeader();
addSection('1.0 Purpose', document.getElementById('sopPurpose').value || 'Not specified.');
addSection('2.0 Scope', document.getElementById('sopScope').value || 'Not specified.');
addSection('3.0 Responsibilities', document.getElementById('sopResponsibilities').value || 'Not specified.');
addSection('4.0 Materials & Equipment', document.getElementById('sopMaterials').value || 'Not specified.');
addSection('5.0 Procedure', document.getElementById('sopProcedure').value || 'Not specified.', true);
addFooter();
doc.save(`SOP_${sopTitle.replace(/\s/g, '_')}.pdf`);
} catch (error) {
console.error("Error generating PDF:", error);
alert("An error occurred while generating the PDF. Please try again.");
} finally {
downloadBtn.textContent = 'Download as Official SOP (PDF)';
downloadBtn.disabled = false;
}
}
showTab(currentTab);
});