Online Real-Time Student Participation Tracker Online Real-Time Student Participation Tracker Tracker Dashboard Session Summary Data Configuration Start Stop Reset Session Time 00:00:00 Participation Summary Student Name Questions Asked Comments Made Total Download Summary as PDF Configure Student List Enter student names below, separated by commas. Click "Update Student List" to apply your changes to the tracker. Student Names Update Student List Previous Next Total Participation: ${totalParticipation} Question ${student.questions} Comment ${student.comments} `; studentTrackerGrid.insertAdjacentHTML('beforeend', card); }); } /** * Renders the summary table. */ function renderSummary() { if (!summaryTableBody) return; summaryTableBody.innerHTML = ''; students.forEach(student => { const total = student.questions + student.comments; const row = ` ${student.name} ${student.questions} ${student.comments} ${total} `; summaryTableBody.insertAdjacentHTML('beforeend', row); }); if (students.length === 0) { summaryTableBody.innerHTML = `No students configured.`; } } /** * Increments a student's participation count. * @param {number} studentId - The ID of the student. * @param {'questions' | 'comments'} type - The type of participation. */ window.incrementParticipation = function(studentId, type) { const student = students.find(s => s.id === studentId); if (student && sessionActive) { student[type]++; renderTracker(); renderSummary(); } else if (!sessionActive) { alert("Please start the session to track participation."); } }; // --- Session Timer Functions --- function startTimer() { if (sessionActive) return; sessionActive = true; timerInterval = setInterval(() => { elapsedSeconds++; updateTimerDisplay(); }, 1000); toggleSessionButtons(true); } function stopTimer() { sessionActive = false; clearInterval(timerInterval); toggleSessionButtons(false); } function resetSession() { stopTimer(); elapsedSeconds = 0; updateTimerDisplay(); students.forEach(s => { s.questions = 0; s.comments = 0; }); renderTracker(); renderSummary(); } function updateTimerDisplay() { const hours = Math.floor(elapsedSeconds / 3600).toString().padStart(2, '0'); const minutes = Math.floor((elapsedSeconds % 3600) / 60).toString().padStart(2, '0'); const seconds = (elapsedSeconds % 60).toString().padStart(2, '0'); timerDisplay.textContent = `${hours}:${minutes}:${seconds}`; } function toggleSessionButtons(isActive) { if(startBtn) startBtn.disabled = isActive; if(stopBtn) stopBtn.disabled = !isActive; if(startBtn) startBtn.classList.toggle('opacity-50', isActive); if(stopBtn) stopBtn.classList.toggle('opacity-50', !isActive); } // --- Tab Navigation --- window.changeTab = function(tabNumber) { currentTab = tabNumber; updateTabVisibility(); }; window.navigateTabs = function(direction) { if (direction === 'next' && currentTab < totalTabs) currentTab++; else if (direction === 'prev' && currentTab > 1) currentTab--; updateTabVisibility(); }; function updateTabVisibility() { Object.values(tabContents).forEach(content => content.classList.add('hidden')); Object.values(tabButtons).forEach(button => button.classList.remove('active')); if (tabContents[currentTab]) tabContents[currentTab].classList.remove('hidden'); if (tabButtons[currentTab]) tabButtons[currentTab].classList.add('active'); updateNavButtons(); } function updateNavButtons() { if (prevBtn) prevBtn.disabled = currentTab === 1; if (nextBtn) nextBtn.disabled = currentTab === totalTabs; if (prevBtn) prevBtn.classList.toggle('opacity-50', currentTab === 1); if (nextBtn) nextBtn.classList.toggle('opacity-50', currentTab === totalTabs); } // --- PDF Generation --- window.downloadPDF = async function() { const { jsPDF } = window.jspdf; const contentArea = document.getElementById('pdf-content-area'); if (!contentArea) { alert("Error: Could not find content to generate PDF."); return; } try { const canvas = await html2canvas(contentArea, { scale: 2 }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const imgProps = pdf.getImageProperties(imgData); const imgHeight = (imgProps.height * pdfWidth) / imgProps.width; let heightLeft = imgHeight; let position = 15; // Initial top margin pdf.setFont("helvetica", "bold"); pdf.setFontSize(16); pdf.text("Student Participation Summary", pdfWidth / 2, 10, { align: 'center' }); pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, imgHeight); heightLeft -= pdfHeight; while (heightLeft >= 0) { position = heightLeft - imgHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, imgHeight); heightLeft -= pdfHeight; } pdf.save('Participation_Summary.pdf'); } catch (error) { console.error("Error generating PDF:", error); alert("An error occurred while generating the PDF."); } }; // --- EVENT LISTENERS --- if(startBtn) startBtn.addEventListener('click', startTimer); if(stopBtn) stopBtn.addEventListener('click', stopTimer); if(resetBtn) resetBtn.addEventListener('click', resetSession); // --- INITIALIZE THE TOOL --- initialize(); });