Publishing Checklist Generator
Your Publication Checklist (Editable)
Go to the "Configuration" tab to select your publication type and generate your checklist.
Publication Details
No checklist items. Please configure and generate the plan.
"; return; } let currentPhase = ""; // Add header row for desktop view if (window.innerWidth > 768) { const headerRow = document.createElement('div'); headerRow.className = 'pub-dash-header'; headerRow.innerHTML = `Checklist Item
Status
Notes
`;
dashboardList.appendChild(headerRow);
}
currentChecklist.forEach(item => {
if (item.phase !== currentPhase) {
// Add Phase Header
const h3 = document.createElement('h3');
h3.textContent = item.phase;
dashboardList.appendChild(h3);
currentPhase = item.phase;
}
const itemEl = document.createElement("div");
itemEl.className = "pub-dash-item";
itemEl.dataset.id = item.id;
itemEl.innerHTML = `
`;
dashboardList.appendChild(itemEl);
});
// Setup listeners for the new elements
setupDashboardListeners();
}
/**
* Attaches listeners to the dashboard elements
*/
function setupDashboardListeners() {
if (!dashboardList) return;
// Listen for all input/change events to update state
dashboardList.querySelectorAll('input, select').forEach(element => {
element.addEventListener('change', handleDashboardUpdate);
element.addEventListener('input', handleDashboardUpdate);
});
// Listen for removal clicks (delegation)
dashboardList.querySelectorAll('button[data-action="remove"]').forEach(button => {
button.addEventListener('click', handleDashboardRemove);
});
}
/**
* Handles updates made directly to items (inputs, selects)
*/
function handleDashboardUpdate(e) {
const itemEl = e.target.closest(".pub-dash-item");
if (!itemEl) return;
const itemId = parseInt(itemEl.dataset.id);
const itemIndex = currentChecklist.findIndex(i => i.id === itemId);
if (itemIndex === -1) return;
const field = e.target.dataset.field;
if (!field) return;
// Update the master state array
currentChecklist[itemIndex][field] = e.target.value;
}
/**
* Handles removing an item directly from the dashboard
*/
function handleDashboardRemove(e) {
const itemEl = e.target.closest(".pub-dash-item");
if (!itemEl) return;
const itemId = parseInt(itemEl.dataset.id);
// Remove from master array
currentChecklist = currentChecklist.filter(item => item.id !== itemId);
// Re-render the dashboard to clean up phase headers
renderDashboard();
}
/**
* Generates a PDF report from the dashboard data
*/
function downloadPDF() {
if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF.autoTable === 'undefined') {
alert("Error: PDF libraries could not be loaded. Please try again.");
return;
}
if (currentChecklist.length === 0) {
alert("Checklist is empty. Please generate a checklist first.");
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF("p", "pt", "a4");
const margin = 40;
let yPos = margin;
const tableHead = [["Item", "Status", "Notes"]];
let currentPhase = "";
// Document Title
doc.setFontSize(18);
doc.text(`Publishing Checklist: ${configTitle.value}`, margin, yPos);
yPos += 15;
doc.setFontSize(10);
doc.setTextColor(100);
doc.text(`Type: ${configType.options[configType.selectedIndex].text} | Target Audience: ${configAudience.value}`, margin, yPos);
yPos += 30;
doc.setTextColor(51); // Reset text color
// Loop through checklist items to create tables grouped by Phase
currentChecklist.forEach(item => {
if (item.phase !== currentPhase) {
// Add new phase header
currentPhase = item.phase;
// Add a page break if too close to bottom
if (yPos > doc.internal.pageSize.getHeight() - 80) {
doc.addPage();
yPos = margin;
}
doc.setFontSize(14);
doc.setFont(undefined, 'bold');
doc.text(currentPhase, margin, yPos);
yPos += 20;
// Start a new table for the phase
doc.autoTable({
startY: yPos,
head: tableHead,
body: [], // Start with an empty body
theme: 'striped',
headStyles: {
fillColor: [0, 115, 230], // Blue
textColor: [255, 255, 255],
fontSize: 10
},
columnStyles: {
0: { cellWidth: 250 },
1: { cellWidth: 60 },
2: { cellWidth: 'auto' },
},
styles: {
fontSize: 9,
cellPadding: 3,
overflow: 'linebreak'
},
margin: { left: margin, right: margin }
});
yPos = doc.autoTable.previous.finalY; // Set Y to where the table ended
}
// Add row to the current table body (hack: access previous table body array)
const lastTableBody = doc.autoTable.previous.body;
if (lastTableBody) {
lastTableBody.push([
item.item,
item.status,
item.notes
]);
}
});
// Re-run the last autoTable call to render the final rows of the last group
if (doc.autoTable.previous) {
doc.autoTable(doc.autoTable.previous.settings);
}
doc.save(`${configTitle.value.replace(/ /g,"_")}_Checklist.pdf`);
}
/**
* Helper to escape HTML
*/
function escapeHTML(str) {
if (!str) return "";
return str
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// --- 4. INITIALIZATION & EVENT LISTENERS ---
// Tab Listeners
tabButtons.forEach((btn) => {
btn.addEventListener("click", () => showTab(btn.dataset.target));
});
navButtons.forEach((btn) => {
btn.addEventListener("click", () => showTab(btn.dataset.target));
});
// Config Tab Listeners
if (generateBtn) {
generateBtn.addEventListener("click", handleGenerate);
}
// Dashboard Tab Listeners (Delegated)
if (dashboardList) {
// Event delegation will handle updates and removal logic
}
// Initial State: Generate a default checklist on load
handleGenerate();
showTab("pub-tab-dashboard");
});
