Festival Schedule Generator

Festival Schedule Generator

Festival Schedule

Edit Performers

Add New Performer

Current Performer List

Stage & Time Configuration

Enter one item per line.

No performers added yet.

"; return; } performers.forEach((p, index) => { const item = document.createElement("div"); item.className = "fsg-performer-item"; item.innerHTML = `
${p.name}
${p.genre}
`; performerList.appendChild(item); }); } /** * Adds a new performer from the input fields. */ function addPerformer() { if (!performerNameInput || !performerGenreInput) return; const name = performerNameInput.value.trim(); const genre = performerGenreInput.value.trim() || "Unknown Genre"; if (!name) { alert("Please enter a performer name."); return; } performers.push({ name, genre }); populatePerformerList(); performerNameInput.value = ""; performerGenreInput.value = ""; } /** * Handles clicks within the performer list (for removal). * @param {Event} e - The click event. */ function handlePerformerListClick(e) { if (e.target.classList.contains("fsg-remove-btn")) { const index = parseInt(e.target.dataset.index, 10); performers.splice(index, 1); populatePerformerList(); } } /** * Shuffles an array in place (Fisher-Yates). * @param {Array} array - The array to shuffle. */ function shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } } /** * Generates the schedule table in Tab 1. */ function generateSchedule() { if (!scheduleHead || !scheduleBody) return; // Clear existing schedule scheduleHead.innerHTML = ""; scheduleBody.innerHTML = ""; if ( performers.length === 0 || stages.length === 0 || timeSlots.length === 0 ) { scheduleBody.innerHTML = 'Please add performers, stages, and time slots in the other tabs!'; return; } // Build Header const headerRow = document.createElement("tr"); headerRow.innerHTML = "Time"; stages.forEach((stage) => { headerRow.innerHTML += `${stage}`; }); scheduleHead.appendChild(headerRow); // Build Body const shuffledPerformers = [...performers]; shuffleArray(shuffledPerformers); let performerIndex = 0; timeSlots.forEach((time) => { const row = document.createElement("tr"); row.innerHTML = `${time}`; stages.forEach(() => { // Cycle through performers const p = shuffledPerformers[performerIndex % performers.length]; performerIndex++; row.innerHTML += ` ${p.name}
${p.genre} `; }); scheduleBody.appendChild(row); }); } /** * Handles downloading the schedule as a PDF. */ function downloadPDF() { if (!scheduleContent || !window.html2canvas || !window.jspdf) { console.error("PDF generation libraries or content not found!"); alert("Error: Could not generate PDF."); return; } // Clone the node const contentToPrint = scheduleContent.cloneNode(true); contentToPrint.classList.add("fsg-pdf-export"); contentToPrint.style.position = "absolute"; contentToPrint.style.left = "-9999px"; contentToPrint.style.top = "0"; contentToPrint.style.width = "900px"; // Fixed width for PDF document.body.appendChild(contentToPrint); html2canvas(contentToPrint, { scale: 2, // Improve resolution useCORS: true, }).then((canvas) => { const imgData = canvas.toDataURL("image/png"); const { jsPDF } = window.jspdf; const pdfWidth = canvas.width; const pdfHeight = canvas.height; const pdf = new jsPDF({ orientation: pdfWidth > pdfHeight ? "l" : "p", // Landscape or Portrait unit: "px", format: [pdfWidth, pdfHeight], }); pdf.addImage(imgData, "PNG", 0, 0, pdfWidth, pdfHeight); pdf.save("festival-schedule.pdf"); // Clean up document.body.removeChild(contentToPrint); }); } // --- INITIALIZE TOOL --- init(); });
Scroll to Top