PLC Meeting Protocol
Meeting Details (Editable)
Meeting Details
Core PLC Questions Focus
Agenda Items
Current Agenda
No agenda items added yet.
No agenda items added yet.
"; return; } agendaItems.forEach(item => { const itemEl = document.createElement("div"); itemEl.className = "plc-agenda-item"; itemEl.dataset.id = item.id; itemEl.innerHTML = ` ${escapeHTML(item.text)} `; configAgendaList.appendChild(itemEl); }); } /** * Handles clicks in the config agenda list (for remove) */ function handleConfigListClick(e) { if (e.target.dataset.action === "remove") { const itemEl = e.target.closest(".plc-agenda-item"); if (itemEl) { agendaItems = agendaItems.filter(item => item.id !== itemEl.dataset.id); updateConfigAgendaDisplay(); // Update this list } } } /** * Populates the dashboard from the config data and agenda items */ function handleGenerateDashboard() { // Transfer basic info dashGroup.value = configGroup.value; dashDate.value = configDate.value; dashFacilitator.value = configFacilitator.value; dashTimekeeper.value = configTimekeeper.value; dashNotetaker.value = configNotetaker.value; // Transfer core questions dashQ1.value = configQ1.value; dashQ2.value = configQ2.value; dashQ3.value = configQ3.value; dashQ4.value = configQ4.value; // Populate dashboard agenda dashAgendaList.innerHTML = ""; // Clear if (agendaItems.length === 0) { const li = document.createElement('li'); li.textContent = 'No agenda items specified.'; dashAgendaList.appendChild(li); } else { agendaItems.forEach(item => { const li = document.createElement('li'); li.className = 'plc-dash-agenda-item'; li.dataset.id = item.id; li.innerHTML = ` `; dashAgendaList.appendChild(li); }); } // Clear action items/decisions dashActions.value = ""; dashDecisions.value = ""; showTab("plc-tab-dashboard"); } /** * Handles removing an item directly from the dashboard agenda */ function handleDashboardAgendaClick(e) { if (e.target.dataset.action === "remove") { const itemEl = e.target.closest(".plc-dash-agenda-item"); if (itemEl) { // Find and remove from master list agendaItems = agendaItems.filter(item => item.id !== itemEl.dataset.id); // Remove from dashboard view itemEl.remove(); // Update config list display updateConfigAgendaDisplay(); // Add message if list becomes empty if (agendaItems.length === 0) { const li = document.createElement('li'); li.textContent = 'No agenda items specified.'; dashAgendaList.appendChild(li); } } } } /** * Updates the master `agendaItems` array when dashboard agenda text changes */ function handleDashboardAgendaInput(e) { const itemEl = e.target.closest(".plc-dash-agenda-item"); if (!itemEl || !e.target.classList.contains('plc-dash-agenda-text')) return; const itemId = itemEl.dataset.id; const item = agendaItems.find(i => i.id === itemId); if (item) { item.text = e.target.value; // Also update the config list display in the background updateConfigAgendaDisplay(); } } /** * Generates a PDF report from the dashboard data */ function downloadPDF() { if (typeof window.jspdf === 'undefined') { alert("Error: PDF library (jsPDF) could not be loaded. Please try again."); return; } // Get potentially edited values from dashboard const group = dashGroup.value || "[Group Name]"; const date = dashDate.value || "[Date]"; const facilitator = dashFacilitator.value || "[Facilitator]"; const timekeeper = dashTimekeeper.value || "[Timekeeper]"; const notetaker = dashNotetaker.value || "[Note Taker]"; const q1 = dashQ1.value || "[Response]"; const q2 = dashQ2.value || "[Response]"; const q3 = dashQ3.value || "[Response]"; const q4 = dashQ4.value || "[Response]"; const actions = dashActions.value || "None recorded."; const decisions = dashDecisions.value || "None recorded."; // Get agenda items from dashboard const agenda = []; const dashAgendaItems = dashAgendaList.querySelectorAll('.plc-dash-agenda-item'); dashAgendaItems.forEach(li => { const input = li.querySelector('.plc-dash-agenda-text'); if (input) agenda.push(input.value); }); const { jsPDF } = window.jspdf; const doc = new jsPDF("p", "pt", "a4"); const margin = 40; let yPos = margin; const lineHeight = 16; const usableWidth = doc.internal.pageSize.getWidth() - margin * 2; // Function to add a section with title and text function addSection(title, text, isBold = false, fontSize = 11) { const titleHeight = 20; const textLines = doc.splitTextToSize(text, usableWidth); const textHeight = textLines.length * lineHeight * (fontSize / 11); // Adjust height for font size if (yPos + titleHeight + textHeight > doc.internal.pageSize.getHeight() - margin) { doc.addPage(); yPos = margin; } doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.text(title, margin, yPos); yPos += lineHeight * 1.5; doc.setFontSize(fontSize); doc.setFont(undefined, isBold ? 'bold' : 'normal'); doc.text(textLines, margin, yPos); yPos += textHeight + lineHeight * 1.5; // Add space after section } // Function to add list items function addList(title, items) { const titleHeight = 20; let listHeight = 0; items.forEach(item => { listHeight += doc.splitTextToSize(`- ${item}`, usableWidth - 15).length * lineHeight; // Indent slightly }); if (yPos + titleHeight + listHeight > doc.internal.pageSize.getHeight() - margin) { doc.addPage(); yPos = margin; } doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.text(title, margin, yPos); yPos += lineHeight * 1.5; doc.setFontSize(11); doc.setFont(undefined, 'normal'); items.forEach(item => { const itemLines = doc.splitTextToSize(`- ${item}`, usableWidth - 15); doc.text(itemLines, margin + 15, yPos); yPos += itemLines.length * lineHeight; }); yPos += lineHeight * 0.5; // Space after list } // Add Title doc.setFontSize(18); doc.setFont(undefined, 'bold'); doc.text("PLC Meeting Protocol", doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += lineHeight * 2; // Add Meeting Details doc.setFontSize(11); doc.setFont(undefined, 'normal'); doc.text(`Group: ${group}`, margin, yPos); doc.text(`Date: ${date}`, margin + 250, yPos); yPos += lineHeight * 1.5; doc.text(`Facilitator: ${facilitator}`, margin, yPos); doc.text(`Timekeeper: ${timekeeper}`, margin + 250, yPos); yPos += lineHeight; doc.text(`Note Taker: ${notetaker}`, margin, yPos); yPos += lineHeight * 2.5; // Add Core Questions addSection("Core Question 1: What do we want students to learn?", q1); addSection("Core Question 2: How will we know if they have learned it?", q2); addSection("Core Question 3: What will we do if they haven't learned it?", q3); addSection("Core Question 4: What will we do if they have learned it?", q4); // Add Agenda addList("Agenda", agenda.length > 0 ? agenda : ["No items specified."]); // Add Actions & Decisions addSection("Action Items / Next Steps", actions); addSection("Decisions Made", decisions); doc.save(`${group.replace(/ /g,"_")}_PLC_Protocol_${date}.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 (addAgendaForm) { addAgendaForm.addEventListener("submit", handleAddAgenda); } if (configAgendaList) { configAgendaList.addEventListener("click", handleConfigListClick); } if (generateBtn) { generateBtn.addEventListener("click", handleGenerateDashboard); } // Dashboard Tab Listeners if (pdfBtn) { pdfBtn.addEventListener("click", downloadPDF); } if (dashAgendaList) { dashAgendaList.addEventListener("click", handleDashboardAgendaClick); dashAgendaList.addEventListener("input", handleDashboardAgendaInput); } // Set default date configDate.valueAsDate = new Date(); // Initial State updateConfigAgendaDisplay(); // Show empty message initially showTab("plc-tab-dashboard"); // Start on dashboard });