Advanced Placement (AP) Course Audit Syllabus Submission Helper

AP Course Audit Syllabus Helper

Syllabus Preview

Configure Your Syllabus

Course Information

Course Details & Materials

Grading Policy

Curricular Requirements (CR)

List each official Curricular Requirement from the College Board's Course and Exam Description (CED) and specify where in your course (e.g., unit, activity, assessment) you provide evidence for it.

${ap_escapeHTML(ap_data.schoolName)}

${ap_escapeHTML(ap_data.academicYear)}

Course Description

${ap_escapeHTML(ap_data.courseDescription).replace(/\n/g, '
')}

Course Materials

Primary Textbook:

${ap_escapeHTML(ap_data.primaryTextbook)}

Other Materials:

    ${ap_data.otherMaterials.map(m => `
  • ${ap_escapeHTML(m)}
  • `).join('')}

Grading Policy

${ap_data.gradingPolicy.map(item => ` `).join('')}
Category Weight
${ap_escapeHTML(item.category)} ${ap_escapeHTML(item.weight)}

Curricular Requirements

${ap_data.curricularRequirements.map(item => ` `).join('')}
Code Requirement Description Teacher Evidence
${ap_escapeHTML(item.code)} ${ap_escapeHTML(item.req).replace(/\n/g, '
')}
${ap_escapeHTML(item.evidence).replace(/\n/g, '
')}
`; } /** * Reads all values from the config tab and updates the ap_data object */ function ap_updateDataFromConfig() { if (!ap_inputCourseName) return; ap_data.courseName = ap_inputCourseName.value; ap_data.teacherName = ap_inputTeacherName.value; ap_data.schoolName = ap_inputSchoolName.value; ap_data.academicYear = ap_inputAcademicYear.value; ap_data.courseDescription = ap_inputDescription.value; ap_data.primaryTextbook = ap_inputTextbook.value; ap_data.otherMaterials = []; ap_materialsContainer.querySelectorAll('.ap-input-material').forEach(input => { if (input.value) ap_data.otherMaterials.push(input.value); }); ap_data.gradingPolicy = []; ap_gradingContainer.querySelectorAll('.flex').forEach(entry => { const id = parseInt(entry.getAttribute('data-id'), 10); const category = entry.querySelector('.ap-input-grading-cat').value; const weight = entry.querySelector('.ap-input-grading-weight').value; if (category || weight) { ap_data.gradingPolicy.push({ id, category, weight }); } }); ap_data.curricularRequirements = []; ap_reqsContainer.querySelectorAll('.border').forEach(entry => { const id = parseInt(entry.getAttribute('data-id'), 10); const code = entry.querySelector('.ap-input-req-code').value; const req = entry.querySelector('.ap-input-req-desc').value; const evidence = entry.querySelector('.ap-input-req-evidence').value; if (code || req || evidence) { ap_data.curricularRequirements.push({ id, code, req, evidence }); } }); } /** * Generates and downloads a multi-page PDF of the dashboard */ async function ap_downloadPDF() { // Check for required libraries if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') { console.error("AP Tool Error: jsPDF or html2canvas library not loaded."); alert("Error: PDF libraries failed to load. Please check console."); return; } // 1. Render the full-size poster into the clone ap_renderDashboard(ap_pdfRenderClone); const { jsPDF } = window.jspdf; try { // 2. Render canvas from the clone const canvas = await html2canvas(ap_pdfRenderClone, { scale: 2, // High resolution useCORS: true, windowWidth: ap_pdfRenderClone.scrollWidth, windowHeight: ap_pdfRenderClone.scrollHeight }); const imgData = canvas.toDataURL('image/png'); const imgWidth = canvas.width; const imgHeight = canvas.height; // Use 'px' for units to match canvas const pdf = new jsPDF({ orientation: 'p', unit: 'px', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); // Scale image height to fit pdf width const ratio = imgWidth / imgHeight; const scaledImgHeight = pdfWidth / ratio; let heightLeft = scaledImgHeight; let position = 0; // y-position of the image on the page // 3. Add the first page pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, scaledImgHeight); heightLeft -= pdfHeight; // 4. Add subsequent pages if needed while (heightLeft > 0) { position -= pdfHeight; // Move the image's y-position up pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, scaledImgHeight); heightLeft -= pdfHeight; } const safeName = (ap_data.courseName || 'syllabus').replace(/[^a-z0-9]/gi, '_').toLowerCase(); pdf.save(`${safeName}_syllabus.pdf`); } catch (error) { console.error("AP Tool Error: PDF generation failed.", error); alert("An error occurred while generating the PDF. Please try again."); } } /** * Utility to escape HTML for display */ function ap_escapeHTML(str) { if (typeof str !== 'string') return ''; return str.replace(/[&<>"']/g, function(m) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[m]; }); } // --- EVENT LISTENERS --- // Tab link clicks ap_tabLinks.forEach((link, index) => { link.addEventListener('click', () => ap_switchTab(index)); }); // Next/Prev button clicks if (ap_prevButton) { ap_prevButton.addEventListener('click', () => { if (ap_currentTab > 0) ap_switchTab(ap_currentTab - 1); }); } if (ap_nextButton) { ap_nextButton.addEventListener('click', () => { if (ap_currentTab < ap_tabLinks.length - 1) ap_switchTab(ap_currentTab + 1); }); } // PDF download if (ap_downloadPdfButton) { ap_downloadPdfButton.addEventListener('click', ap_downloadPDF); } // --- Config Tab "Add" Buttons --- if (ap_addMaterialButton) { ap_addMaterialButton.addEventListener('click', () => ap_addMaterialInput('', ap_materialCounter++)); } if (ap_addGradingButton) { ap_addGradingButton.addEventListener('click', () => ap_addGradingInput()); } if (ap_addReqButton) { ap_addReqButton.addEventListener('click', () => ap_addReqInput()); } // --- Config Tab "Remove" Buttons (Event Delegation) --- if (ap_configTab) { ap_configTab.addEventListener('click', (e) => { if (e.target.classList.contains('ap-remove-material')) { e.target.closest('.flex').remove(); } if (e.target.classList.contains('ap-remove-grading')) { e.target.closest('.flex').remove(); } if (e.target.classList.contains('ap-remove-req')) { e.target.closest('.border').remove(); } }); // Auto-update dashboard on config changes ap_configTab.addEventListener('change', () => { ap_updateDataFromConfig(); if (ap_currentTab === 0) { ap_renderDashboard(ap_dashboardOutput); } }); } // --- INITIALIZATION --- ap_initSampleData(); ap_renderConfig(); ap_renderDashboard(ap_dashboardOutput); // Set initial tab state ap_tabPanes.forEach((pane, index) => { pane.classList.toggle('hidden', index !== 0); pane.classList.toggle('ap-active', index === 0); }); });
Scroll to Top