- ${Object.entries(ceremony.pairs).map(([p1, p2]) => `
${p1} - ${p2}
`).join('')}
+
+ ${Object.entries(ceremony.pairs).map(([p1, p2]) => `
+
+ ${p1}
+ ${p2}
+
+ `).join('')}
`;
ceremonyList.appendChild(el);
@@ -508,39 +464,29 @@ Kayla
const selectedG2Names = [];
for (const select of pairSelectors) {
- const g1Name = select.dataset.g1Name;
const g2Name = select.value;
- if (!g2Name) return showError(`Please select a match for ${g1Name}.`);
+ if (!g2Name) return showError("Incomplete ceremony! Pair everyone.");
selectedG2Names.push(g2Name);
- pairs[g1Name] = g2Name;
+ pairs[select.dataset.g1Name] = g2Name;
}
- if (new Set(selectedG2Names).size !== selectedG2Names.length) {
- return showError("Each person from Group 2 can only be matched once per ceremony.");
- }
+ if (new Set(selectedG2Names).size !== selectedG2Names.length) return showError("Duplicate selection in ceremony!");
const beams = parseInt(ceremonyBeams.value, 10);
- if (isNaN(beams) || beams < 0 || beams > group1Names.length) {
- return showError(`Beams must be a number between 0 and ${group1Names.length}.`);
- }
-
const ceremony = { id: Date.now(), pairs, beams };
ceremonies.push(ceremony);
renderCeremonyUI(ceremony, ceremonies.length);
- ceremonyForm.reset();
}
function handleRemoveCeremony(e) {
const idToRemove = Number(e.target.dataset.id);
ceremonies = ceremonies.filter(c => c.id !== idToRemove);
- e.target.closest('.ceremony-item').remove();
ceremonyList.innerHTML = '';
ceremonies.forEach((c, i) => renderCeremonyUI(c, i + 1));
}
async function handleCalculate() {
showLoading();
-
try {
const payload = {
group1: group1Names,
@@ -555,26 +501,22 @@ Kayla
body: JSON.stringify(payload)
});
- if (!res.ok) {
- throw new Error(`Server error: ${res.statusText}`);
- }
-
+ if (!res.ok) throw new Error("Backend malfunction");
const results = await res.json();
totalPossibilitiesText.textContent = results.possibilities.toLocaleString();
resultsDisplay.classList.remove("hidden");
if (results.possibilities === 0) {
- showError("Impossible scenario. The data entered contradicts itself.");
+ showError("Impossible scenario detected!");
probTableBody.innerHTML = '';
probTableHead.innerHTML = '';
} else {
displayProbabilityGrid(results.grid_data);
+ gridSection.scrollIntoView({ behavior: 'smooth' });
}
-
} catch (e) {
- console.error(e);
- showError("An error occurred connecting to the backend API.");
+ showError("Connection failed");
} finally {
hideLoading();
}
@@ -582,70 +524,50 @@ Kayla
function displayProbabilityGrid(gridData) {
probTableHead.innerHTML = `
-
- |
- ${gridData.columns.map(name => `${name} | `).join('')}
+
+ |
+ ${gridData.columns.map(name => `${name} | `).join('')}
`;
probTableBody.innerHTML = gridData.index.map((g1Name, rowIndex) => `
-
- | ${g1Name} |
+
+ | ${g1Name} |
${gridData.columns.map((g2Name, colIndex) => {
const prob = gridData.data[rowIndex][colIndex] * 100;
let cellClass = 'prob-possible';
- if (prob === 100) cellClass = 'prob-100';
- else if (prob === 0) cellClass = 'prob-0';
- return `${prob.toFixed(1)}% | `;
+ if (prob >= 99.9) cellClass = 'prob-100';
+ else if (prob <= 0.1) cellClass = 'prob-0';
+ return `${prob.toFixed(1)}% | `;
}).join('')}
`).join('');
}
function handleSaveConfig() {
- if (group1Names.length === 0) return showError("Please set contestants before saving.");
const state = { group1Names, group2Names, truthBooths, ceremonies };
const blob = new Blob([JSON.stringify(state, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
- a.href = url;
- a.download = 'ayto-save.json';
- document.body.appendChild(a);
+ a.href = url; a.download = 'ayto-save.json';
a.click();
- document.body.removeChild(a);
- URL.revokeObjectURL(url);
}
function handleLoadConfig() { fileLoader.click(); }
-
- function handleFileSelected(e) {
+ fileLoader.addEventListener("change", (e) => {
const file = e.target.files[0];
- if (!file) return;
const reader = new FileReader();
- reader.onload = (event) => {
- try { loadState(JSON.parse(event.target.result)); }
- catch (err) { showError("Failed to load file."); }
+ reader.onload = (ev) => {
+ const s = JSON.parse(ev.target.result);
+ g1NamesText.value = s.group1Names.join('\n');
+ g2NamesText.value = s.group2Names.join('\n');
+ handleSetupContestants();
+ truthBooths = s.truthBooths; ceremonies = s.ceremonies;
+ truthBooths.forEach(renderTruthBoothUI);
+ ceremonies.forEach((c, i) => renderCeremonyUI(c, i + 1));
};
reader.readAsText(file);
- e.target.value = null;
- }
-
- function loadState(state) {
- if (!state.group1Names || !state.group2Names || !state.truthBooths || !state.ceremonies) {
- return showError("Invalid save file. Required fields are missing.");
- }
- g1NamesText.value = state.group1Names.join('\n');
- g2NamesText.value = state.group2Names.join('\n');
- if (!handleSetupContestants()) return;
-
- truthBooths = state.truthBooths;
- ceremonies = state.ceremonies;
-
- truthBooths.forEach(renderTruthBoothUI);
- ceremonies.forEach((c, i) => renderCeremonyUI(c, i + 1));
-
- handleCalculate();
- }
+ });
setupButton.addEventListener("click", handleSetupContestants);
tbForm.addEventListener("submit", handleAddTruthBooth);
@@ -653,8 +575,6 @@ Kayla
calculateButton.addEventListener("click", handleCalculate);
saveButton.addEventListener("click", handleSaveConfig);
loadButton.addEventListener("click", handleLoadConfig);
- fileLoader.addEventListener("change", handleFileSelected);
-
\ No newline at end of file