This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { OptimisticAction } from "./OptimisticAction.js";
export class PollManager extends OptimisticAction {
constructor() {
super();
document.addEventListener("click", (event) => this.onClick(event));
document.addEventListener("submit", (event) => this.onSubmit(event), true);
}
onClick(event) {
const option = event.target.closest(".poll-option");
if (option && !option.disabled) {
event.preventDefault();
this.vote(option);
return;
}
const toggle = event.target.closest("[data-poll-toggle]");
if (toggle) {
event.preventDefault();
this.toggleBuilder(toggle);
return;
}
const addOption = event.target.closest("[data-poll-add-option]");
if (addOption) {
event.preventDefault();
this.addOption(addOption);
return;
}
const removeOption = event.target.closest("[data-poll-remove-option]");
if (removeOption) {
event.preventDefault();
this.removeOption(removeOption);
}
}
async vote(option) {
const poll = option.closest(".poll");
if (!poll) {
return;
}
const pollUid = poll.dataset.pollUid;
const optionUid = option.dataset.optionUid;
await this.submit(`/polls/${pollUid}/vote`, { option_uid: optionUid }, null, (result) => this.render(poll, result));
}
render(poll, result) {
const byUid = {};
(result.options || []).forEach((option) => {
byUid[option.uid] = option;
});
poll.querySelectorAll(".poll-option").forEach((button) => {
const data = byUid[button.dataset.optionUid];
if (!data) {
return;
}
const chosen = result.my_choice === data.uid;
button.classList.toggle("chosen", chosen);
button.setAttribute("aria-pressed", chosen ? "true" : "false");
const bar = button.querySelector(".poll-option-bar");
if (bar) {
bar.style.width = `${data.pct}%`;
}
const pct = button.querySelector(".poll-option-pct");
if (pct) {
pct.textContent = `${data.pct}%`;
}
const check = button.querySelector(".poll-option-check");
if (check) {
check.hidden = !chosen;
}
});
const total = poll.querySelector(".poll-total");
if (total) {
total.textContent = `${result.total} vote${result.total === 1 ? "" : "s"}`;
}
}
toggleBuilder(toggle) {
const form = toggle.closest("form");
const builder = form ? form.querySelector("[data-poll-builder]") : null;
if (!builder) {
return;
}
const activating = builder.hidden;
builder.hidden = !activating;
this.setPollEnabled(builder, activating);
const label = toggle.querySelector("[data-poll-toggle-label]");
if (label) {
label.textContent = activating ? "Remove poll" : "Add poll";
}
}
setPollEnabled(builder, enabled) {
builder.querySelectorAll("input[name='poll_question'], input[name='poll_options']").forEach((input) => {
input.disabled = !enabled;
if (!enabled) {
input.value = "";
}
});
const error = builder.querySelector("[data-poll-error]");
if (error) {
error.hidden = true;
error.textContent = "";
}
}
addOption(button) {
const form = button.closest("form");
const container = form ? form.querySelector("[data-poll-options]") : null;
if (!container) {
return;
}
const rows = container.querySelectorAll(".poll-builder-row");
if (rows.length >= 6) {
return;
}
const row = document.createElement("div");
row.className = "poll-builder-row";
const input = document.createElement("input");
input.type = "text";
input.name = "poll_options";
input.maxLength = 100;
input.placeholder = `Option ${rows.length + 1}`;
const remove = document.createElement("button");
remove.type = "button";
remove.className = "poll-builder-remove";
remove.dataset.pollRemoveOption = "";
remove.setAttribute("aria-label", "Remove option");
remove.textContent = "×";
row.appendChild(input);
row.appendChild(remove);
container.appendChild(row);
}
removeOption(button) {
const container = button.closest("[data-poll-options]");
if (!container) {
return;
}
if (container.querySelectorAll(".poll-builder-row").length <= 2) {
return;
}
const row = button.closest(".poll-builder-row");
if (row) {
row.remove();
}
}
onSubmit(event) {
const form = event.target;
if (!form || typeof form.querySelector !== "function") {
return;
}
const builder = form.querySelector("[data-poll-builder]");
if (!builder || builder.hidden) {
return;
}
const question = builder.querySelector("input[name='poll_question']");
const options = [...builder.querySelectorAll("input[name='poll_options']")]
.map((input) => input.value.trim())
.filter(Boolean);
let problem = "";
if (!question || !question.value.trim()) {
problem = "Add a poll question, or remove the poll.";
} else if (options.length < 2) {
problem = "Add at least two poll options, or remove the poll.";
}
if (problem) {
event.preventDefault();
event.stopImmediatePropagation();
const error = builder.querySelector("[data-poll-error]");
if (error) {
error.textContent = problem;
error.hidden = false;
}
}
}
}