doc-fui-ds
Version:
Doc
812 lines (668 loc) • 35.2 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Random Spin Wheel</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- SweetAlert2 -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- XLSX for Excel Handling -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<style>
.wheel-container {
position: relative;
width: 300px;
height: 300px;
margin: 20px auto;
}
#wheel {
width: 100%;
height: 100%;
border-radius: 50%;
transition: transform 4s cubic-bezier(0.17, 0.67, 0.83, 0.67);
}
.arrow {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
border-bottom: 30px solid red;
}
.winner-item {
background: #f8f9fa;
padding: 5px 10px;
margin: 5px 0;
border-radius: 5px;
border-left: 5px solid #28a745;
}
</style>
</head>
<body class="bg-light">
<div class="container mt-4">
<div class="row">
<!-- Left Section: Wheel -->
<div class="col-md-7 text-center">
<h1 class="mb-3 text-primary">🎡 Random Spin Wheel 🎡</h1>
<!-- Upload file -->
<input type="file" id="fileInput" accept=".xls, .xlsx" class="form-control mb-3">
<!-- Text Area for Input Data -->
<textarea id="nameInput" class="form-control mb-3" placeholder="Enter names (one per line)..." rows="4"></textarea>
<div class="mb-3">
<label for="winnerLimit" class="form-label">Set Winner Limit:</label>
<input type="number" id="winnerLimit" class="form-control" min="1" value="1">
</div>
<!-- Update & Search Buttons -->
<div class="input-group mb-3">
<input type="text" id="searchInput" placeholder="Search name..." class="form-control" aria-describedby="searchButton">
<button id="searchButton" class="btn btn-secondary">Search</button>
<button id="resetSearchButton" class="btn btn-warning mt-2">Reset Search</button>
</div>
<!-- List Display with Search and Delete Option -->
<div id="nameList" class="mt-3"></div>
<div class="mb-3">
<button id="addButton" class="btn btn-success">Add Data to Spin Wheel</button>
<button id="updateButton" class="btn btn-primary" style="display: none;">Update Spin Wheel Data</button>
</div>
<div class="">
<button id="drawButton" class="btn btn-primary me-2" style="display: none;">Spin the Wheel</button>
<button id="resetButton" class="btn btn-danger" style="display: none;">Reset Game</button>
</div>
<div class="">
<button id="shuffleButton" class="btn btn-primary mt-3">Shuffle Data</button>
<button id="sortButton" class="btn btn-secondary mt-3">Sort Data</button>
</div>
<div class="">
<button id="downloadInputTxtButton" class="btn btn-secondary mt-3">Download Input Data (.txt)</button>
<button id="downloadInputExcelButton" class="btn btn-secondary mt-3">Download Input Data (.xlsx)</button>
<button id="downloadInputCsvButton" class="btn btn-secondary mt-3">Download Input Data (.csv)</button>
</div>
<div class="wheel-container">
<div class="arrow"></div>
<svg id="wheel" width="300" height="300" viewBox="0 0 300 300"></svg>
</div>
</div>
<!-- Right Section: Winner List -->
<div class="col-md-5">
<h2 class="text-success">🏆 Winners</h2>
<div id="winnerList" class="border rounded p-3 bg-white"></div>
<button id="downloadTxtButton" class="btn btn-success mt-3">Download Winners (.txt)</button>
<button id="downloadExcelButton" class="btn btn-info mt-3">Download Winners (.xlsx)</button>
<button id="downloadCsvButton" class="btn btn-warning mt-3">Download Winners (.csv)</button>
</div>
</div>
</div>
<!-- Modal Structure -->
<div class="modal fade" id="adsModal" tabindex="-1" aria-labelledby="adsModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="adsModalLabel">Sponsored Ad</h5>
</div>
<div class="modal-body" id="adContent">
<p>Loading Ad...</p>
</div>
</div>
</div>
</div>
<script>
let namesArray = [];
let rotation = 0;
document.getElementById('fileInput').addEventListener('change', function (event) {
const file = event.target.files[0];
if (!file) return;
const fileType = file.name.split('.').pop().toLowerCase();
const reader = new FileReader();
if (fileType === 'txt') {
// Handle .txt file
reader.onload = function (e) {
document.getElementById('nameInput').value = e.target.result;
};
reader.readAsText(file);
} else if (fileType === 'xls' || fileType === 'xlsx') {
// Handle Excel file
reader.onload = function (e) {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
// Extract data from the first sheet and first column
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 });
// Extract names from the first column
const names = rows.map(row => row[0]).filter(name => name); // Remove empty values
// Insert names into textarea
document.getElementById('nameInput').value = names.join('\n');
};
reader.readAsArrayBuffer(file);
} else {
// alert('Unsupported file type. Please upload a .txt, .xls, or .xlsx file.');
// ✅ Show SweetAlert2 warning when no names are available
Swal.fire({
title: "Unsupported file type.😕",
text: "lease upload a .txt, .xls, or .xlsx file.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
return;
}
});
document.getElementById("drawButton").addEventListener("click", function () {
if (namesArray.length === 0) {
Swal.fire({
title: "Oops! No Names Found 😕",
text: "Please enter names before spinning the wheel.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
return;
}
// ✅ Get the winner limit from user input
let winnerLimit = parseInt(document.getElementById("winnerLimit").value) || 1;
// ✅ Prevent multiple spins at the same time
document.getElementById("drawButton").disabled = true;
// ✅ Generate and spin the wheel
generateWheel();
spinWheel(winnerLimit);
});
function generateWheel() {
let wheel = document.getElementById("wheel");
wheel.innerHTML = ""; // Clear previous segments
let totalSegments = namesArray.length;
let sliceAngle = 360 / totalSegments;
for (let i = 0; i < totalSegments; i++) {
let angle = i * sliceAngle;
let color = `hsl(${(i * 360) / totalSegments}, 80%, 60%)`;
let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", describeArc(150, 150, 150, angle, angle + sliceAngle));
path.setAttribute("fill", color);
path.setAttribute("stroke", "#fff");
path.setAttribute("stroke-width", "2");
wheel.appendChild(path);
// Text positioning
let text = document.createElementNS("http://www.w3.org/2000/svg", "text");
let textAngle = angle + sliceAngle / 2; // Center of the slice
let textX = 150 + Math.cos((textAngle - 90) * Math.PI / 180) * 100; // Adjusted for diagonal alignment
let textY = 150 + Math.sin((textAngle - 90) * Math.PI / 180) * 100;
text.setAttribute("x", textX);
text.setAttribute("y", textY);
text.setAttribute("transform", `rotate(${textAngle + 90}, ${textX}, ${textY})`); // Rotates text diagonally
text.setAttribute("text-anchor", "middle");
text.setAttribute("font-size", "14px");
text.setAttribute("fill", "#fff");
text.setAttribute("dominant-baseline", "middle"); // Center align text vertically
text.textContent = namesArray[i];
wheel.appendChild(text);
}
}
function addWinner(name) {
let winnerList = document.getElementById("winnerList");
let winnerItem = document.createElement("div");
winnerItem.classList.add("winner-item", "d-flex", "justify-content-between", "align-items-center", "p-2", "border", "rounded", "mb-2", "bg-light");
let winnerText = document.createElement("span");
winnerText.textContent = name;
let deleteBtn = document.createElement("button");
deleteBtn.textContent = "❌";
deleteBtn.classList.add("btn", "btn-sm", "btn-danger", "ms-2");
deleteBtn.onclick = function () {
confirmDeleteWinner(winnerItem, name);
};
winnerItem.appendChild(winnerText);
winnerItem.appendChild(deleteBtn);
winnerList.appendChild(winnerItem);
}
function confirmDeleteWinner(winnerItem, name) {
Swal.fire({
title: "Are you sure?",
text: `Do you want to remove ${name} from the winner list?`,
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#d33",
cancelButtonColor: "#3085d6",
confirmButtonText: "Yes, delete it!"
}).then((result) => {
if (result.isConfirmed) {
deleteWinner(winnerItem, name);
}
});
}
function deleteWinner(winnerItem, name) {
winnerItem.remove(); // Remove the winner from the list
// ✅ Add the deleted name back to the namesArray so they can be drawn again
if (!namesArray.includes(name)) {
namesArray.push(name);
}
// ✅ Check if the draw button should be enabled
let winnerLimit = parseInt(document.getElementById("winnerLimit").value) || 1;
let currentWinners = document.getElementById("winnerList").children.length;
if (currentWinners < winnerLimit) {
document.getElementById("drawButton").disabled = false;
}
}
function spinWheel(winnerLimit) {
let totalSegments = namesArray.length;
let sliceAngle = 360 / totalSegments;
let randomIndex = Math.floor(Math.random() * totalSegments);
let finalRotation = 360 * 5 + (randomIndex * sliceAngle) + (sliceAngle / 2);
let wheel = document.getElementById("wheel");
rotation += finalRotation;
wheel.style.transform = `rotate(${rotation}deg)`;
setTimeout(() => {
let actualRotation = rotation % 360;
let winningIndex = Math.floor((360 - actualRotation) / sliceAngle) % totalSegments;
let winner = namesArray[winningIndex];
// ✅ Check if winner limit has been reached
let currentWinners = document.getElementById("winnerList").children.length;
if (currentWinners >= winnerLimit) {
Swal.fire({
title: "Winner Limit Reached!",
text: `You have already selected ${winnerLimit} winners.`,
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
// ✅ Re-enable the spin button
document.getElementById("drawButton").disabled = false;
return;
}
Swal.fire({
title: "🎉 Winner Selected! 🎉",
text: `${winner} is the lucky winner! 🏆`,
icon: "success",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
// ✅ Add winner to the winner list
let winnerList = document.getElementById("winnerList");
let winnerItem = document.createElement("div");
winnerItem.classList.add("winner-item", "d-flex", "justify-content-between", "align-items-center", "p-2", "border", "rounded", "mb-2", "bg-light");
let winnerText = document.createElement("span");
winnerText.textContent = `🏆 ${winner}`;
let deleteBtn = document.createElement("button");
deleteBtn.textContent = "❌";
deleteBtn.classList.add("btn", "btn-sm", "btn-danger", "ms-2");
deleteBtn.onclick = function () {
confirmDeleteWinner(winnerItem, winner);
};
winnerItem.appendChild(winnerText);
winnerItem.appendChild(deleteBtn);
winnerList.appendChild(winnerItem);
// ✅ Remove winner from namesArray
namesArray.splice(winningIndex, 1);
// ✅ Disable the spin button if only one name remains
if (namesArray.length <= 1) {
document.getElementById("drawButton").disabled = true;
} else {
// ✅ Re-enable the spin button after selecting a winner
document.getElementById("drawButton").disabled = false;
}
// ✅ Check if all winners have been selected
if (namesArray.length === 0 || document.getElementById("winnerList").children.length >= winnerLimit) {
setTimeout(() => {
Swal.fire({
title: "Game Over! 🎊",
text: "All winners have been selected!",
icon: "info",
confirmButtonText: "OK"
});
}, 2000);
}
}, 5000);
}
function describeArc(x, y, radius, startAngle, endAngle) {
let start = polarToCartesian(x, y, radius, endAngle);
let end = polarToCartesian(x, y, radius, startAngle);
let largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
return [
"M", x, y,
"L", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y,
"Z"
].join(" ");
}
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
let angleInRadians = (angleInDegrees - 90) * Math.PI / 180;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
// Function to shuffle input data
document.getElementById("shuffleButton").addEventListener("click", function () {
let inputData = document.getElementById("nameInput").value.trim().split("\n");
if (inputData.length === 0 || (inputData.length === 1 && inputData[0] === "")) {
Swal.fire({
title: "No Input Data!",
text: "Please enter or upload names before shuffling.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
return;
}
inputData = inputData.sort(() => Math.random() - 0.5);
document.getElementById("nameInput").value = inputData.join("\n");
});
// Function to sort input data
document.getElementById("sortButton").addEventListener("click", function () {
let inputData = document.getElementById("nameInput").value.trim().split("\n");
if (inputData.length === 0 || (inputData.length === 1 && inputData[0] === "")) {
Swal.fire({
title: "No Input Data!",
text: "Please enter or upload names before sorting.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
return;
}
inputData = inputData.sort();
document.getElementById("nameInput").value = inputData.join("\n");
});
// Function to toggle draw and reset buttons
function toggleButtons() {
let drawButton = document.getElementById("drawButton");
let resetButton = document.getElementById("resetButton");
if (namesArray.length > 0) {
drawButton.style.display = "block";
resetButton.style.display = "block";
} else {
drawButton.style.display = "none";
resetButton.style.display = "none";
}
}
// Function to add input data
document.getElementById("addButton").addEventListener("click", function () {
let newData = document.getElementById("nameInput").value.trim().split("\n");
let newNames = newData.map(name => name.trim()).filter(name => name !== "");
namesArray = [...new Set([...namesArray, ...newNames])]; // Merge unique names
updateTextArea();
displayNames();
toggleButtons();
// ✅ Hide Add Button & Show Update Button when data is added
if (namesArray.length > 0) {
document.getElementById("addButton").style.display = "none";
document.getElementById("updateButton").style.display = "block";
}
// ✅ Generate wheel after adding data
generateWheel();
Swal.fire({
title: "Data Added!",
text: "The new names have been added successfully.",
icon: "success",
confirmButtonText: "OK",
confirmButtonColor: "#28a745"
});
});
// Function to update input data
document.getElementById("updateButton").addEventListener("click", function () {
let updatedData = document.getElementById("nameInput").value.trim().split("\n");
let updatedNames = updatedData.map(name => name.trim()).filter(name => name !== "");
namesArray = updatedNames; // Replace the current list with the new input
updateTextArea();
displayNames();
toggleButtons();
// ✅ Ensure Update Button stays visible if data exists
if (namesArray.length > 0) {
document.getElementById("updateButton").style.display = "block";
document.getElementById("addButton").style.display = "none";
} else {
document.getElementById("updateButton").style.display = "none";
document.getElementById("addButton").style.display = "block"; // Show Add Button if empty
}
// ✅ Generate wheel after updating data
generateWheel();
Swal.fire({
title: "List Updated!",
text: "The input names have been updated successfully.",
icon: "success",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
});
// ✅ Reset Button Click Event
document.getElementById("resetButton").addEventListener("click", function () {
Swal.fire({
title: "Are you sure?",
text: "This will clear all data, reset the name list, and refresh the wheel.",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#dc3545",
cancelButtonColor: "#6c757d",
confirmButtonText: "Yes, Reset"
}).then((result) => {
if (result.isConfirmed) {
// ✅ Clear the text area
document.getElementById("nameInput").value = "";
// ✅ Clear the winner list
document.getElementById("winnerList").innerHTML = "";
// ✅ Clear the name list
document.getElementById("nameList").innerHTML = "";
// ✅ Reset the names array
namesArray = [];
// ✅ Completely remove and recreate the wheel SVG
let wheelContainer = document.querySelector(".wheel-container");
let oldWheel = document.getElementById("wheel");
if (oldWheel) {
oldWheel.parentNode.removeChild(oldWheel); // Remove old SVG element
}
let newWheel = document.createElementNS("http://www.w3.org/2000/svg", "svg");
newWheel.setAttribute("id", "wheel");
newWheel.setAttribute("width", "300");
newWheel.setAttribute("height", "300");
newWheel.setAttribute("viewBox", "0 0 300 300");
wheelContainer.appendChild(newWheel); // Append new empty wheel
// ✅ Reset the rotation
rotation = 0;
// ✅ Reset file input so users can re-upload Excel after reset
document.getElementById("fileInput").value = "";
// ✅ Hide Draw, Update, and Reset buttons
document.getElementById("drawButton").style.display = "none";
document.getElementById("updateButton").style.display = "none";
document.getElementById("addButton").style.display = "block";
Swal.fire({
title: "Game Reset!",
text: "The spin wheel, name list, and winners have been cleared.",
icon: "success",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
}
});
});
// Function to update textarea with current namesArray
function updateTextArea() {
document.getElementById("nameInput").value = namesArray.join("\n");
}
// Function to display and filter the list with delete option
function displayNames(searchText = "", filter = false) {
let nameListDiv = document.getElementById("nameList");
nameListDiv.innerHTML = "";
let filteredNames = filter ? namesArray.filter(name => name.toLowerCase().includes(searchText.toLowerCase())) : namesArray;
filteredNames.forEach((name) => {
let listItem = document.createElement("div");
listItem.classList.add("d-flex", "justify-content-between", "align-items-center", "p-2", "border", "rounded", "mb-2", "bg-light");
let nameText = document.createElement("span");
nameText.textContent = name;
let deleteButton = document.createElement("button");
deleteButton.textContent = "❌";
deleteButton.classList.add("btn", "btn-danger", "btn-sm", "ms-2");
// ✅ Correctly delete the clicked item
deleteButton.onclick = function () {
let nameIndex = namesArray.indexOf(name);
if (nameIndex !== -1) {
namesArray.splice(nameIndex, 1);
}
updateTextArea();
displayNames();
toggleButtons();
// ✅ Regenerate wheel after deletion
generateWheel();
};
listItem.appendChild(nameText);
listItem.appendChild(deleteButton);
nameListDiv.appendChild(listItem);
});
}
// Function to search input data
document.getElementById("searchButton").addEventListener("click", function () {
let searchText = document.getElementById("searchInput").value.trim();
displayNames(searchText, true);
});
// Function to reset search
document.getElementById("resetSearchButton").addEventListener("click", function () {
document.getElementById("searchInput").value = "";
displayNames();
});
// Show the name list and toggle buttons when input data is added or updated
displayNames();
toggleButtons();
// ✅ Ads image list
const adsArray = [
"<img src='https://via.placeholder.com/300x250?text=Ad+1' alt='Ad 1'>",
"<img src='https://via.placeholder.com/300x250?text=Ad+2' alt='Ad 2'>",
"<img src='https://via.placeholder.com/300x250?text=Ad+3' alt='Ad 3'>"
];
// ✅ Ads modal after clicking on download button
function showAdModal(callback) {
let randomAd = adsArray[Math.floor(Math.random() * adsArray.length)];
document.getElementById("adContent").innerHTML = `<span id='countdown'>5</span><br>` + randomAd;
let modal = new bootstrap.Modal(document.getElementById("adsModal"));
modal.show();
let countdown = 5;
const countdownElem = document.getElementById("countdown");
const interval = setInterval(() => {
countdown--;
countdownElem.textContent = countdown;
if (countdown <= 0) clearInterval(interval);
}, 1000);
setTimeout(() => {
modal.hide();
callback();
}, 5000);
}
// ✅ Function to download winner list as a .txt file
document.getElementById("downloadTxtButton").addEventListener("click", function () {
let winnerList = document.getElementById("winnerList").children;
if (winnerList.length === 0) {
Swal.fire({
title: "No Winners Yet!",
text: "There are no winners to download.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
return;
}
showAdModal(() => {
let winners = Array.from(winnerList).map(item => item.textContent).join("\n");
let blob = new Blob([winners], { type: "text/plain" });
let link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "WinnerList.txt";
link.click();
});
});
// ✅ Function to download winner list as an .xlsx (Excel) file
document.getElementById("downloadExcelButton").addEventListener("click", function () {
let winnerList = document.getElementById("winnerList").children;
if (winnerList.length === 0) {
Swal.fire({
title: "No Winners Yet!",
text: "There are no winners to download.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
return;
}
showAdModal(() => {
let winners = Array.from(winnerList).map(item => [item.textContent]);
let worksheet = XLSX.utils.aoa_to_sheet([["Winner List"], ...winners]);
let workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Winners");
let excelBuffer = XLSX.write(workbook, { bookType: "xlsx", type: "array" });
let blob = new Blob([excelBuffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
let link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "WinnerList.xlsx";
link.click();
});
});
// ✅ Function to download winner list as an .csv (CSV) file
document.getElementById("downloadCsvButton").addEventListener("click", function () {
let winnerList = document.getElementById("winnerList").children;
if (winnerList.length === 0) {
Swal.fire({
title: "No Winners Yet!",
text: "There are no winners to download.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
return;
}
showAdModal(() => {
let winners = Array.from(winnerList).map(item => item.textContent).join("\n");
let csvContent = "data:text/csv;charset=utf-8," + "Winner List\n" + winners;
let encodedUri = encodeURI(csvContent);
let link = document.createElement("a");
link.href = encodedUri;
link.download = "WinnerList.csv";
link.click();
});
});
// Function to download input data in all formats
function downloadInputData(format) {
let inputData = document.getElementById("nameInput").value.trim();
if (!inputData) {
Swal.fire({
title: "No Input Data!",
text: "Please enter or upload names before downloading.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
return;
}
showAdModal(() => {
if (format === "txt") {
let blob = new Blob([inputData], { type: "text/plain" });
let link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "InputData.txt";
link.click();
} else if (format === "xlsx") {
let names = inputData.split("\n").map(name => [name]);
let worksheet = XLSX.utils.aoa_to_sheet([["Input Data"], ...names]);
let workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Input Data");
let excelBuffer = XLSX.write(workbook, { bookType: "xlsx", type: "array" });
let blob = new Blob([excelBuffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
let link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "InputData.xlsx";
link.click();
} else if (format === "csv") {
let csvContent = "data:text/csv;charset=utf-8," + "Input Data\n" + inputData.replace(/\n/g, "\n");
let encodedUri = encodeURI(csvContent);
let link = document.createElement("a");
link.href = encodedUri;
link.download = "InputData.csv";
link.click();
}
});
}
document.getElementById("downloadInputTxtButton").addEventListener("click", () => downloadInputData("txt"));
document.getElementById("downloadInputExcelButton").addEventListener("click", () => downloadInputData("xlsx"));
document.getElementById("downloadInputCsvButton").addEventListener("click", () => downloadInputData("csv"));
</script>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>