No units added yet.
";
return;
}
modules.forEach(m => {
const itemEl = document.createElement("div");
itemEl.className = "scsg-config-list-item";
itemEl.dataset.id = m.id;
itemEl.innerHTML = `
${escapeHTML(m.title)} (${m.duration} Weeks)
`;
configModuleList.appendChild(itemEl);
});
}
// --- Dashboard Management ---
function renderDashboard() {
// Get all editable content from config inputs
const data = {
courseName: configCourseName.value || "[Course Name]",
teacher: configTeacher.value || "[Teacher Name]",
room: configRoom.value || "[Room/Period]",
year: configYear.value || "[Year]",
desc: configDesc.value || "[Course Description]",
grading: configGrading.value || "[Grading Policy]",
objectives: configObjectives.value || "[Learning Objectives]",
};
// --- Build Dashboard HTML ---
dashboardOutput.innerHTML = `
${escapeHTML(data.courseName)} Syllabus (${escapeHTML(data.year)})
Unit Breakdown & Timeline
| Unit/Module |
Duration (Weeks) |
Major Assessment |
Action |
`;
// Populate Unit Table
const tbody = dashboardOutput.querySelector('#scsg-dash-units tbody');
modules.forEach(m => {
const tr = document.createElement('tr');
tr.dataset.id = m.id;
tr.innerHTML = `
|
|
|
|
`;
tbody.appendChild(tr);
});
setupDashboardListeners();
showTab('scsg-tab-dashboard');
}
/**
* Attaches listeners to the newly rendered dashboard elements for editing/removal
*/
function setupDashboardListeners() {
const table = dashboardOutput.querySelector('#scsg-dash-units');
if (!table) return;
// Event delegation for removal
table.addEventListener('click', (e) => {
if (e.target.dataset.action === 'remove-module') {
const tr = e.target.closest('tr');
modules.splice(modules.findIndex(m => m.id === tr.dataset.id), 1);
// Re-render dashboard to update the table entirely
renderDashboard();
updateConfigModuleDisplay();
}
});
// Event delegation for input/change updates
table.addEventListener('input', handleDashboardUpdate);
table.addEventListener('change', handleDashboardUpdate);
}
/**
* Handles updates made directly to the dashboard inputs/textareas/table cells
*/
function handleDashboardUpdate(e) {
const target = e.target;
const field = target.dataset.field;
// 1. Handle Module Table Updates
if (target.closest('#scsg-dash-units')) {
const tr = target.closest('tr');
const moduleId = tr.dataset.id;
const module = modules.find(m => m.id === moduleId);
if (module && field) {
module[field] = target.type === 'number' ? parseInt(target.value) : target.value;
}
return;
}
// 2. Handle Simple Textarea/Input Updates
const map = {
'scsg-dash-teacher': configTeacher,
'scsg-dash-room': configRoom,
'scsg-dash-desc': configDesc,
'scsg-dash-objectives': configObjectives,
'scsg-dash-grading': configGrading
};
const configInput = map[target.id];
if (configInput) {
configInput.value = target.value;
}
}
/**
* Generates a PDF report from the dashboard data
*/
function downloadPDF() {
if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF.autoTable === 'undefined') {
alert("Error: PDF library could not be loaded. Please try again.");
return;
}
try {
const { jsPDF } = window.jspdf;
const doc = new jsPDF("p", "pt", "a4");
const margin = 40;
let yPos = margin;
// Get final edited data from the dashboard inputs/textareas
const courseName = configCourseName.value || "Course Syllabus";
const courseYear = configYear.value || "Year";
const teacher = dashboardOutput.querySelector("#scsg-dash-teacher")?.value || "";
const room = dashboardOutput.querySelector("#scsg-dash-room")?.value || "";
const desc = dashboardOutput.querySelector("#scsg-dash-desc")?.value || "N/A";
const objectives = dashboardOutput.querySelector("#scsg-dash-objectives")?.value || "N/A";
const grading = dashboardOutput.querySelector("#scsg-dash-grading")?.value || "N/A";
// Get Table Data
const tableBody = Array.from(dashboardOutput.querySelectorAll('#scsg-dash-units tbody tr')).map(tr => [
tr.querySelector('[data-field="title"]')?.value || '',
tr.querySelector('[data-field="duration"]')?.value || '',
tr.querySelector('[data-field="assessment"]')?.value || ''
]);
// --- PDF Title & Header ---
doc.setFontSize(20);
doc.setFont(undefined, 'bold');
doc.text(courseName, doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' });
yPos += 20;
doc.setFontSize(14);
doc.text(`Syllabus (${courseYear})`, doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' });
yPos += 30;
doc.setFontSize(10);
doc.setFont(undefined, 'normal');
doc.text(`Teacher: ${teacher}`, margin, yPos);
doc.text(`Room/Period: ${room}`, margin + 200, yPos);
yPos += 25;
// Function to add a section with title and text
function addSection(title, content) {
const textLines = doc.splitTextToSize(content, doc.internal.pageSize.getWidth() - margin * 2);
const textHeight = textLines.length * 12;
if (yPos > doc.internal.pageSize.getHeight() - 80) {
doc.addPage();
yPos = margin;
}
doc.setFontSize(14);
doc.setFont(undefined, 'bold');
doc.text(title, margin, yPos);
yPos += 18;
doc.setFontSize(10);
doc.setFont(undefined, 'normal');
doc.text(textLines, margin, yPos);
yPos += textHeight + 15;
}
// 1. Course Description
addSection('Course Description', desc);
// 2. Learning Objectives
addSection('Learning Objectives', objectives);
// 3. Grading Policy
addSection('Grading Policy', grading);
// 4. Unit Breakdown Table
if (tableBody.length > 0) {
if (yPos > doc.internal.pageSize.getHeight() - 150) {
doc.addPage();
yPos = margin;
}
doc.setFontSize(14);
doc.setFont(undefined, 'bold');
doc.text('Unit Breakdown & Timeline', margin, yPos);
yPos += 20;
doc.autoTable({
startY: yPos,
head: [['Unit/Module', 'Duration (Weeks)', 'Major Assessment']],
body: tableBody,
theme: 'striped',
headStyles: { fillColor: [0, 115, 230], textColor: [255, 255, 255], fontSize: 10 },
styles: { fontSize: 9, cellPadding: 4, overflow: 'linebreak' },
columnStyles: { 0: { cellWidth: 180 }, 1: { cellWidth: 80, halign: 'center' }, 2: { cellWidth: 'auto' } },
margin: { left: margin, right: margin }
});
}
doc.save(`${courseName.replace(/ /g,"_")}_Syllabus_${courseYear}.pdf`);
} catch (error) {
console.error("PDF Generation Error:", error);
alert("An error occurred during PDF creation. Please ensure all data fields are filled correctly.");
}
}
/**
* 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 (addModuleForm) {
addModuleForm.addEventListener("submit", handleAddModule);
}
if (configModuleList) {
configModuleList.addEventListener("click", handleRemoveModule);
}
if (generateBtn) {
generateBtn.addEventListener("click", renderDashboard);
}
// PDF Button
if (pdfBtn) {
pdfBtn.addEventListener("click", downloadPDF);
}
// Initial config list display
updateConfigModuleDisplay();
// Initial State: Generate dashboard with samples
renderDashboard();
showTab("scsg-tab-dashboard");
});