Dependencies: ${escapeHTML(data.dependencies)}
Code Location: ${escapeHTML(data.codeLocation)}
Execution Command: ${escapeHTML(data.executionCommand)}
3. Reproducibility Status
| Checklist Item |
Status |
| Raw Data Snapshot Frozen? |
${escapeHTML(data.statusDataFrozen)} |
| Container/VM Configuration Available? |
${escapeHTML(data.statusContainer)} |
| Comprehensive README Present? |
${escapeHTML(data.statusReadme)} |
| Final Results Manually Validated? |
${escapeHTML(data.statusResultsValidated)} |
4. Final Notes & Caveats
${formatParagraphs(data.reproNotes)}
`;
};
const downloadTxt = () => {
const data = getChecklistData();
let content = `REPRODUCIBILITY CHECKLIST: ${data.title.toUpperCase()}\n`;
content += "========================================================\n\n";
content += `Author: ${data.author}\nDate: ${data.date}\n\n`;
content += "1. DATA SOURCING\n";
content += "--------------------\n";
content += `Raw Data Source: ${data.dataSource}\n`;
content += `Pre-processing Steps: ${data.dataPreprocessed}\n\n`;
content += "2. ENVIRONMENT & CODE\n";
content += "---------------------\n";
content += `Required Environment: ${data.environment}\n`;
content += `Dependencies: ${data.dependencies}\n`;
content += `Code Location: ${data.codeLocation}\n`;
content += `Execution Command: ${data.executionCommand}\n\n`;
content += "3. REPRODUCIBILITY STATUS\n";
content += "---------------------------\n";
content += `Raw Data Snapshot Frozen?:\t${data.statusDataFrozen}\n`;
content += `Container/VM Available?:\t${data.statusContainer}\n`;
content += `Comprehensive README Present?:\t${data.statusReadme}\n`;
content += `Results Manually Validated?:\t${data.statusResultsValidated}\n\n`;
content += "4. FINAL NOTES & CAVEATS\n";
content += "--------------------------\n";
content += data.reproNotes;
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = `repro_checklist_${data.title.replace(/ /g, '_')}.txt`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(a.href);
};
const downloadPDF = () => {
if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') {
alert('Error: jsPDF library not loaded.');
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'mm', 'a4');
const data = getChecklistData();
const margin = 20;
const pageWidth = doc.internal.pageSize.getWidth();
const usableWidth = pageWidth - (margin * 2);
let yPos = 20;
const addTitle = (text, isMain = false) => {
if (yPos > 270) { doc.addPage(); yPos = 20; }
yPos += 5;
doc.setFontSize(isMain ? 16 : 14);
doc.setFont(undefined, 'bold');
doc.setTextColor(isMain ? 44 : 26, isMain ? 62 : 188, isMain ? 80 : 156);
doc.text(text, margin, yPos);
yPos += isMain ? 8 : 6;
};
const addDetail = (label, text, indent = false, code = false) => {
if (yPos > 280) { doc.addPage(); yPos = 20; }
doc.setFontSize(11);
doc.setFont(undefined, 'bold');
doc.setTextColor(52, 73, 94);
doc.text(label, margin + (indent ? 5 : 0), yPos);
doc.setFont(undefined, code ? 'normal' : 'normal'); // Use normal font for text, can set 'courier' for code if needed
doc.setTextColor(52, 73, 94);
let startX = margin + 35;
let textToSplit = text;
if (label.length > 0) {
// Check if label pushes text off screen
const labelWidth = doc.getStringUnitWidth(label) * doc.internal.getFontSize();
if (labelWidth > 40) startX = margin;
}
const splitText = doc.splitTextToSize(textToSplit, usableWidth - (indent ? 5 : 0) - (label.length > 0 ? 5 : 0));
doc.text(splitText, startX, yPos);
yPos += (splitText.length * 6) + 2;
};
// --- Build PDF Document ---
addTitle("Reproducibility Checklist", true);
addTitle(data.title, 14, [52, 73, 94], 'center', 'normal');
yPos += 5;
addDetail("Author/Team:", data.author);
addDetail("Date:", data.date);
yPos += 5;
// 1. Data Sourcing
addTitle("1. Data Sourcing", false);
addDetail("Source:", data.dataSource);
addDetail("Pre-processing:", data.dataPreprocessed);
// 2. Environment & Code
addTitle("2. Environment & Code", false);
addDetail("Environment:", data.environment);
addDetail("Dependencies:", data.dependencies);
addDetail("Code Location:", data.codeLocation);
addDetail("Execution Cmd:", data.executionCommand, false, true);
// 3. Reproducibility Status (Table)
addTitle("3. Reproducibility Status", false);
const statusHead = [['Checklist Item', 'Status']];
const statusBody = [
['Raw Data Snapshot Frozen?', data.statusDataFrozen],
['Container/VM Configuration Available?', data.statusContainer],
['Comprehensive README Present?', data.statusReadme],
['Final Results Manually Validated?', data.statusResultsValidated]
];
doc.autoTable({
startY: yPos,
head: statusHead,
body: statusBody,
theme: 'grid',
headStyles: { fillColor: [26, 188, 156], textColor: [255, 255, 255], fontSize: 11 },
styles: { fontSize: 10, cellPadding: 3, textColor: [52, 73, 94] },
columnStyles: { 1: { fontStyle: 'bold', halign: 'center', cellWidth: 30 } },
margin: { left: margin, right: margin }
});
yPos = doc.autoTable.previous ? (doc.autoTable.previous.finalY + 10) : (yPos + 30);
// 4. Final Notes
addTitle("4. Final Notes & Caveats", false);
addDetail("", data.reproNotes, true);
doc.save(`repro_checklist_${data.title.replace(/ /g, '_')}.pdf`);
};
// --- Event Listeners ---
// Tab Buttons
tabButtons.forEach((btn, index) => {
btn.addEventListener('click', () => showTab(index + 1));
});
// Next/Prev Navigation
nextBtn.addEventListener('click', () => showTab(currentTab + 1));
prevBtn.addEventListener('click', () => showTab(currentTab - 1));
// Tab 4 Actions
downloadPdfBtn.addEventListener('click', downloadPDF);
downloadTxtBtn.addEventListener('click', downloadTxt);
// --- Initialization ---
showTab(1);
});